From 4f24447193be2477580e8aa05126545fb01232b0 Mon Sep 17 00:00:00 2001 From: Boopathi Date: Thu, 21 May 2026 13:21:32 +0530 Subject: [PATCH 1/5] clutter/color-state-params: Export EOTF and color space mapping helpers Make clutter_eotf_apply(), clutter_eotf_apply_inv(), and clutter_color_state_params_get_color_space_mapping() public so they can be reused outside of the color state params implementation. --- clutter/clutter/clutter-color-state-params.c | 6 +++--- clutter/clutter/clutter-color-state-params.h | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/clutter/clutter/clutter-color-state-params.c b/clutter/clutter/clutter-color-state-params.c index e85b3db91d0..9ff37b39a20 100644 --- a/clutter/clutter/clutter-color-state-params.c +++ b/clutter/clutter/clutter-color-state-params.c @@ -305,7 +305,7 @@ clutter_eotf_apply_gamma (float input, powf (input, gamma_exp); } -static float +float clutter_eotf_apply (ClutterEOTF eotf, float input) { @@ -335,7 +335,7 @@ clutter_eotf_apply (ClutterEOTF eotf, return input; } -static float +float clutter_eotf_apply_inv (ClutterEOTF eotf, float input) { @@ -1468,7 +1468,7 @@ clutter_color_state_params_get_from_XYZ (ClutterColorStateParams *color_state_pa graphene_matrix_multiply (matrix, &from_XYZ, matrix); } -static void +void clutter_color_state_params_get_color_space_mapping (ClutterColorStateParams *color_state_params, ClutterColorStateParams *target_color_state_params, graphene_matrix_t *out_color_space_mapping) diff --git a/clutter/clutter/clutter-color-state-params.h b/clutter/clutter/clutter-color-state-params.h index bec38dec842..b7209431cc1 100644 --- a/clutter/clutter/clutter-color-state-params.h +++ b/clutter/clutter/clutter-color-state-params.h @@ -189,4 +189,17 @@ void clutter_color_state_params_do_tone_mapping (ClutterColorState *color_state, float *data, int n_samples); +CLUTTER_EXPORT +float clutter_eotf_apply (ClutterEOTF eotf, + float input); + +CLUTTER_EXPORT +float clutter_eotf_apply_inv (ClutterEOTF eotf, + float input); + +CLUTTER_EXPORT +void clutter_color_state_params_get_color_space_mapping (ClutterColorStateParams *color_state_params, + ClutterColorStateParams *target_color_state_params, + graphene_matrix_t *out_color_space_mapping); + G_END_DECLS -- GitLab From 13de7fad16a695e89fb31d25c70e62f27b13d0c6 Mon Sep 17 00:00:00 2001 From: Boopathi Date: Thu, 21 May 2026 13:21:50 +0530 Subject: [PATCH 2/5] clutter/stage-view: Add HW color pipeline bypass flag Add use_hw_color_pipeline flag and getter/setter to ClutterStageView. When set, the GPU shader-based color transform in the offscreen pipeline is bypassed, allowing DRM HW color management to take over. --- clutter/clutter/clutter-stage-view-private.h | 7 ++++ clutter/clutter/clutter-stage-view.c | 44 ++++++++++++++++---- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h index 31ac7e144ea..a0e338991eb 100644 --- a/clutter/clutter/clutter-stage-view-private.h +++ b/clutter/clutter/clutter-stage-view-private.h @@ -83,5 +83,12 @@ CLUTTER_EXPORT void clutter_stage_view_set_output_color_state (ClutterStageView *view, ClutterColorState *color_state); +CLUTTER_EXPORT +void clutter_stage_view_set_use_hw_color_pipeline (ClutterStageView *view, + gboolean use_hw); + +CLUTTER_EXPORT +gboolean clutter_stage_view_get_use_hw_color_pipeline (ClutterStageView *view); + CLUTTER_EXPORT const char * clutter_stage_view_get_name (ClutterStageView *view); diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c index aedd5f6cf91..69cb613e4f2 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c @@ -105,6 +105,7 @@ typedef struct _ClutterStageViewPrivate guint dirty_viewport : 1; guint dirty_projection : 1; guint needs_update_devices : 1; + guint use_hw_color_pipeline : 1; } ClutterStageViewPrivate; G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageView, clutter_stage_view, G_TYPE_OBJECT) @@ -259,11 +260,14 @@ ensure_stage_view_offscreen_pipeline (ClutterStageView *view) cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix); } - clutter_color_state_add_pipeline_transform (priv->color_state, - priv->output_color_state, - pipeline, - CLUTTER_COLOR_STATE_TRANSFORM_OPAQUE); + if (!priv->use_hw_color_pipeline) + { + clutter_color_state_add_pipeline_transform (priv->color_state, + priv->output_color_state, + pipeline, + CLUTTER_COLOR_STATE_TRANSFORM_OPAQUE); + } g_set_object (&priv->offscreen_pipeline, g_steal_pointer (&pipeline)); } @@ -293,9 +297,12 @@ clutter_stage_view_invalidate_offscreen (ClutterStageView *view) clutter_stage_view_schedule_update (view); } - if (priv->transform == MTK_MONITOR_TRANSFORM_NORMAL && - !clutter_color_state_needs_mapping (priv->color_state, - priv->output_color_state)) + if (priv->transform == MTK_MONITOR_TRANSFORM_NORMAL + && ( + priv->use_hw_color_pipeline || + !clutter_color_state_needs_mapping (priv->color_state, + priv->output_color_state)) + ) { g_clear_object (&priv->offscreen_pipeline); g_clear_object (&priv->offscreen); @@ -354,6 +361,29 @@ clutter_stage_view_set_output_color_state (ClutterStageView *view, color_state); } +void +clutter_stage_view_set_use_hw_color_pipeline (ClutterStageView *view, + gboolean use_hw) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + if (priv->use_hw_color_pipeline == !!use_hw) + return; + + priv->use_hw_color_pipeline = !!use_hw; + clutter_stage_view_invalidate_offscreen (view); +} + +gboolean +clutter_stage_view_get_use_hw_color_pipeline (ClutterStageView *view) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + return priv->use_hw_color_pipeline; +} + static void clutter_stage_view_ensure_color_states (ClutterStageView *view) { -- GitLab From dc3fb48a42930500a1e77245660e9a094ce42acb Mon Sep 17 00:00:00 2001 From: Boopathi Date: Thu, 21 May 2026 13:22:03 +0530 Subject: [PATCH 3/5] backends/native: Add meta_kms_crtc_has_color_pipeline() and fix CTM detection Add a helper to check whether a CRTC supports the full hardware color pipeline (degamma + CTM + gamma). Also fix the CTM supported flag to be set when the property exists, not only when a blob is programmed. --- src/backends/native/meta-kms-crtc.c | 15 +++++++++++++-- src/backends/native/meta-kms-crtc.h | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c index 8d9692ce4e9..d01d6f935fe 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -134,6 +134,16 @@ meta_kms_crtc_set_is_leased (MetaKmsCrtc *crtc, crtc->is_leased = leased; } +gboolean +meta_kms_crtc_has_color_pipeline (MetaKmsCrtc *crtc) +{ + const MetaKmsCrtcState *state = &crtc->current_state; + + return state->degamma.supported && + state->ctm.supported && + state->gamma.supported; +} + static void read_crtc_lut (MetaKmsCrtc *crtc, MetaKmsImplDevice *impl_device, @@ -300,6 +310,9 @@ read_crtc_ctm (MetaKmsCrtc *crtc, if (!prop_ctm->prop_id) return; + /* Allocate internal structure for CTM */ + crtc_state->ctm.supported = TRUE; + blob_id = prop_ctm->value; if (blob_id == 0) return; @@ -317,8 +330,6 @@ read_crtc_ctm (MetaKmsCrtc *crtc, drm_ctm = blob->data; - /* Allocate internal structure for CTM */ - crtc_state->ctm.supported = TRUE; crtc_state->ctm.value = meta_ctm_new (); /* Copy the 3x3 matrix from KMS blob */ diff --git a/src/backends/native/meta-kms-crtc.h b/src/backends/native/meta-kms-crtc.h index 789a8531f16..6fb694090e9 100644 --- a/src/backends/native/meta-kms-crtc.h +++ b/src/backends/native/meta-kms-crtc.h @@ -80,6 +80,8 @@ gboolean meta_kms_crtc_is_active (MetaKmsCrtc *crtc); gboolean meta_kms_crtc_is_leased (MetaKmsCrtc *crtc); +gboolean meta_kms_crtc_has_color_pipeline (MetaKmsCrtc *crtc); + void meta_kms_crtc_set_presentation_time (MetaKmsCrtc *crtc, int64_t presentation_us); -- GitLab From c9ab105a0fc9460ab5863cb98e79b041ef1badfc Mon Sep 17 00:00:00 2001 From: Boopathi Date: Thu, 21 May 2026 13:22:15 +0530 Subject: [PATCH 4/5] backends/native: Handle NULL CTM in atomic modesetting When the CTM state pointer is NULL, set the blob ID to 0 (bypass) instead of trying to create a blob. This allows clearing the CTM when color management is not needed. --- .../native/meta-kms-impl-device-atomic.c | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index d024428267b..0b8fb1cb8b0 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -871,23 +871,34 @@ process_crtc_color_updates (MetaKmsImplDevice *impl_device, if (color_update->ctm.has_update) { MetaCtm *ctm = color_update->ctm.state; - struct drm_color_ctm drm_color_ctm; uint32_t ctm_blob_id = 0; - int i; - for (i = 0; i < 9; i++) - drm_color_ctm.matrix[i] = ctm->matrix[i]; + if (ctm) + { + struct drm_color_ctm drm_color_ctm; + int i; - ctm_blob_id = store_new_blob (impl_device, blob_ids, - &drm_color_ctm, sizeof drm_color_ctm, - error); - if (!ctm_blob_id) - return FALSE; + for (i = 0; i < 9; i++) + drm_color_ctm.matrix[i] = ctm->matrix[i]; - meta_topic (META_DEBUG_KMS, - "[atomic] Setting CRTC (%u, %s) ctm", - meta_kms_crtc_get_id (crtc), - meta_kms_impl_device_get_path (impl_device)); + ctm_blob_id = store_new_blob (impl_device, blob_ids, + &drm_color_ctm, sizeof drm_color_ctm, + error); + if (!ctm_blob_id) + return FALSE; + + meta_topic (META_DEBUG_KMS, + "[atomic] Setting CRTC (%u, %s) ctm", + meta_kms_crtc_get_id (crtc), + meta_kms_impl_device_get_path (impl_device)); + } + else + { + meta_topic (META_DEBUG_KMS, + "[atomic] Setting CRTC (%u, %s) ctm to bypass", + meta_kms_crtc_get_id (crtc), + meta_kms_impl_device_get_path (impl_device)); + } if (!add_crtc_property (impl_device, crtc, req, META_KMS_CRTC_PROP_CTM, -- GitLab From 3cbcc8556ab9348e9e92ae40bd5473190f4e1508 Mon Sep 17 00:00:00 2001 From: Boopathi Date: Thu, 21 May 2026 13:23:00 +0530 Subject: [PATCH 5/5] backends/native: Offload color management to DRM HW color pipeline When the CRTC supports degamma, CTM, and gamma properties, program them directly instead of using the GPU shader path. The degamma LUT linearizes with the source EOTF, the CTM handles color space conversion with luminance mapping, and the gamma LUT applies the inverse target EOTF composed with Night Light/VCGT corrections. --- src/backends/meta-renderer-view.c | 19 ++ src/backends/native/meta-onscreen-native.c | 331 ++++++++++++++++++++- 2 files changed, 341 insertions(+), 9 deletions(-) diff --git a/src/backends/meta-renderer-view.c b/src/backends/meta-renderer-view.c index 113d8fbbd6e..7748212d02f 100644 --- a/src/backends/meta-renderer-view.c +++ b/src/backends/meta-renderer-view.c @@ -35,6 +35,8 @@ #include "backends/meta-color-device.h" #include "backends/meta-crtc.h" #include "backends/meta-renderer.h" +#include "backends/native/meta-crtc-kms.h" +#include "backends/native/meta-kms-crtc.h" #include "clutter/clutter-mutter.h" #include "core/boxes-private.h" #include "core/meta-debug-control-private.h" @@ -110,6 +112,23 @@ set_color_states (MetaRendererView *view) view_color_state); clutter_stage_view_set_output_color_state (clutter_stage_view, output_color_state); + + if (META_IS_CRTC_KMS (priv->crtc)) + { + MetaCrtcKms *crtc_kms = META_CRTC_KMS (priv->crtc); + MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); + gboolean use_hw = meta_kms_crtc_has_color_pipeline (kms_crtc); + + clutter_stage_view_set_use_hw_color_pipeline (clutter_stage_view, + use_hw); + + if (use_hw) + { + meta_topic (META_DEBUG_RENDER, + "View %s: using DRM color pipeline (degamma+CTM+gamma)", + clutter_stage_view_get_name (clutter_stage_view)); + } + } } static void diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index bf3e9ffc101..0bc51b83e54 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -51,6 +51,7 @@ #include "backends/native/meta-renderer-native-gles3.h" #include "backends/native/meta-renderer-native-private.h" #include "backends/native/meta-egl-gbm.h" +#include "clutter/clutter-color-state-params.h" #include "cogl/cogl.h" #include "cogl/cogl-context-private.h" #include "cogl/cogl-display-private.h" @@ -161,8 +162,9 @@ struct _MetaOnscreenNative struct { KmsProperty gamma_lut; KmsProperty privacy_screen; + KmsProperty color_pipeline; } property; - KmsProperty properties[2]; + KmsProperty properties[3]; }; }; @@ -2331,6 +2333,171 @@ meta_onscreen_native_before_redraw (CoglOnscreen *onscreen, maybe_update_vrr (onscreen_native, frame); } +static uint64_t +float_to_s31_32 (float val) +{ + uint64_t result; + + if (val < 0.0f) + { + result = (uint64_t) (-val * (double) (1ULL << 32)); + result |= 1ULL << 63; + } + else + { + result = (uint64_t) (val * (double) (1ULL << 32)); + } + + return result; +} + +static MetaGammaLut * +generate_degamma_lut (ClutterEOTF eotf, + int size) +{ + MetaGammaLut *lut; + int i; + + lut = meta_gamma_lut_new_sized (size); + + for (i = 0; i < size; i++) + { + float t = (float) i / (float) (size - 1); + float val = clutter_eotf_apply (eotf, t); + uint16_t encoded = (uint16_t) (CLAMP (val, 0.0f, 1.0f) * 65535.0f + 0.5f); + + lut->red[i] = encoded; + lut->green[i] = encoded; + lut->blue[i] = encoded; + } + + return lut; +} + +/* + * Compute luminance mapping scalar between source and target. + * + * The GPU shader path applies this as a separate stage: + * color = luminance_mapping * color + * but the HW pipeline has no dedicated luminance stage, so we fold it + * into the CTM matrix. + */ +static float +get_hw_lum_mapping (const ClutterLuminance *lum, + const ClutterLuminance *target_lum) +{ + return (target_lum->ref / lum->ref) * (lum->max / target_lum->max); +} + +static void +generate_ctm (ClutterColorStateParams *source_params, + ClutterColorStateParams *target_params, + MetaCtm *ctm) +{ + graphene_matrix_t mapping; + const ClutterLuminance *lum; + const ClutterLuminance *target_lum; + float lum_scale; + float m[16]; + + clutter_color_state_params_get_color_space_mapping (source_params, + target_params, + &mapping); + + /* + * Fold luminance mapping into the CTM. + * The GPU shader does: linear -> lum_scale -> matrix -> inv_eotf + * Since lum_scale is a scalar multiply in linear space, it commutes + * with the color space matrix: (S * M) = M' where M' = S * M. + */ + lum = clutter_color_state_params_get_luminance (source_params); + target_lum = clutter_color_state_params_get_luminance (target_params); + lum_scale = get_hw_lum_mapping (lum, target_lum); + + if (lum_scale != 1.0f) + { + graphene_matrix_t scale_matrix; + + graphene_matrix_init_scale (&scale_matrix, + lum_scale, lum_scale, lum_scale); + graphene_matrix_multiply (&scale_matrix, &mapping, &mapping); + } + + graphene_matrix_to_float (&mapping, m); + + /* + * graphene_matrix_t is column-major 4x4. + * DRM CTM (struct drm_color_ctm) is row-major 3x3 in S31.32 + * sign-magnitude format. + * + * Column-major 4x4 layout: m[col*4 + row] + * m[0]=r0c0 m[4]=r0c1 m[8]=r0c2 + * m[1]=r1c0 m[5]=r1c1 m[9]=r1c2 + * m[2]=r2c0 m[6]=r2c1 m[10]=r2c2 + */ + ctm->matrix[0] = float_to_s31_32 (m[0]); + ctm->matrix[1] = float_to_s31_32 (m[4]); + ctm->matrix[2] = float_to_s31_32 (m[8]); + ctm->matrix[3] = float_to_s31_32 (m[1]); + ctm->matrix[4] = float_to_s31_32 (m[5]); + ctm->matrix[5] = float_to_s31_32 (m[9]); + ctm->matrix[6] = float_to_s31_32 (m[2]); + ctm->matrix[7] = float_to_s31_32 (m[6]); + ctm->matrix[8] = float_to_s31_32 (m[10]); +} + +static MetaGammaLut * +generate_gamma_lut (ClutterEOTF eotf, + int size, + const MetaGammaLut *base_gamma) +{ + MetaGammaLut *lut; + int i; + + lut = meta_gamma_lut_new_sized (size); + + for (i = 0; i < size; i++) + { + float t = (float) i / (float) (size - 1); + float val = clutter_eotf_apply_inv (eotf, t); + + val = CLAMP (val, 0.0f, 1.0f); + + if (base_gamma && base_gamma->size > 1) + { + float idx_f = val * (float) (base_gamma->size - 1); + int idx = (int) idx_f; + float frac = idx_f - (float) idx; + + if (idx >= (int) base_gamma->size - 1) + { + lut->red[i] = base_gamma->red[base_gamma->size - 1]; + lut->green[i] = base_gamma->green[base_gamma->size - 1]; + lut->blue[i] = base_gamma->blue[base_gamma->size - 1]; + } + else + { + lut->red[i] = (uint16_t) (base_gamma->red[idx] * (1.0f - frac) + + base_gamma->red[idx + 1] * frac + 0.5f); + lut->green[i] = (uint16_t) (base_gamma->green[idx] * (1.0f - frac) + + base_gamma->green[idx + 1] * frac + 0.5f); + lut->blue[i] = (uint16_t) (base_gamma->blue[idx] * (1.0f - frac) + + base_gamma->blue[idx + 1] * frac + 0.5f); + } + } + else + { + uint16_t encoded = (uint16_t) (val * 65535.0f + 0.5f); + + lut->red[i] = encoded; + lut->green[i] = encoded; + lut->blue[i] = encoded; + } + } + + return lut; +} + void meta_onscreen_native_prepare_frame (CoglOnscreen *onscreen, ClutterFrame *frame) @@ -2345,17 +2512,33 @@ meta_onscreen_native_prepare_frame (CoglOnscreen *onscreen, if (onscreen_native->property.gamma_lut.invalidated) { - const MetaGammaLut *gamma; - MetaKmsUpdate *kms_update; - - kms_update = meta_frame_native_ensure_kms_update (frame_native, - kms_device); - - gamma = meta_crtc_kms_peek_gamma_lut (crtc_kms); - meta_kms_update_set_crtc_gamma (kms_update, kms_crtc, gamma); onscreen_native->property.gamma_lut.invalidated = FALSE; onscreen_native->property.gamma_lut.target_frame_counter = target_frame_counter; + if (meta_kms_crtc_has_color_pipeline (kms_crtc)) + { + /* + * When the HW color pipeline is active, gamma is composed with + * the inverse EOTF. Defer to the color_pipeline block below by + * marking it invalidated so the full pipeline is regenerated + * with the updated base gamma (Night Light / VCGT). + */ + onscreen_native->property.color_pipeline.invalidated = TRUE; + } + else + { + const MetaGammaLut *gamma; + MetaKmsUpdate *kms_update; + + kms_update = meta_frame_native_ensure_kms_update (frame_native, + kms_device); + + gamma = meta_crtc_kms_peek_gamma_lut (crtc_kms); + meta_kms_update_set_crtc_gamma (kms_update, kms_crtc, gamma); + onscreen_native->property.gamma_lut.invalidated = FALSE; + onscreen_native->property.gamma_lut.target_frame_counter = + target_frame_counter; + } } if (onscreen_native->property.privacy_screen.invalidated) @@ -2374,6 +2557,69 @@ meta_onscreen_native_prepare_frame (CoglOnscreen *onscreen, onscreen_native->property.privacy_screen.target_frame_counter = target_frame_counter; } + + if (onscreen_native->property.color_pipeline.invalidated && + meta_kms_crtc_has_color_pipeline (kms_crtc)) + { + ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (onscreen_native->view); + ClutterColorState *color_state = + clutter_stage_view_get_color_state (stage_view); + ClutterColorState *output_color_state = + clutter_stage_view_get_output_color_state (stage_view); + + if (clutter_color_state_needs_mapping (color_state, output_color_state) && + CLUTTER_IS_COLOR_STATE_PARAMS (color_state) && + CLUTTER_IS_COLOR_STATE_PARAMS (output_color_state)) + { + ClutterColorStateParams *source_params = + CLUTTER_COLOR_STATE_PARAMS (color_state); + ClutterColorStateParams *target_params = + CLUTTER_COLOR_STATE_PARAMS (output_color_state); + const ClutterEOTF *source_eotf = + clutter_color_state_params_get_eotf (source_params); + const ClutterEOTF *output_eotf = + clutter_color_state_params_get_eotf (target_params); + const MetaKmsCrtcState *crtc_state = + meta_kms_crtc_get_current_state (kms_crtc); + const MetaGammaLut *base_gamma = + meta_crtc_kms_peek_gamma_lut (crtc_kms); + g_autoptr (MetaGammaLut) degamma = NULL; + g_autoptr (MetaGammaLut) gamma = NULL; + MetaCtm ctm; + MetaKmsUpdate *kms_update; + + kms_update = meta_frame_native_ensure_kms_update (frame_native, + kms_device); + + degamma = generate_degamma_lut (*source_eotf, + crtc_state->degamma.size); + generate_ctm (source_params, target_params, &ctm); + gamma = generate_gamma_lut (*output_eotf, + crtc_state->gamma.size, + base_gamma); + + meta_kms_update_set_crtc_degamma (kms_update, kms_crtc, degamma); + meta_kms_update_set_crtc_ctm (kms_update, kms_crtc, &ctm); + meta_kms_update_set_crtc_gamma (kms_update, kms_crtc, gamma); + } + else + { + MetaKmsUpdate *kms_update; + const MetaGammaLut *base_gamma = + meta_crtc_kms_peek_gamma_lut (crtc_kms); + + kms_update = meta_frame_native_ensure_kms_update (frame_native, + kms_device); + + meta_kms_update_set_crtc_degamma (kms_update, kms_crtc, NULL); + meta_kms_update_set_crtc_ctm (kms_update, kms_crtc, NULL); + meta_kms_update_set_crtc_gamma (kms_update, kms_crtc, base_gamma); + } + + onscreen_native->property.color_pipeline.invalidated = FALSE; + onscreen_native->property.color_pipeline.target_frame_counter = + target_frame_counter; + } } static void @@ -2946,12 +3192,53 @@ create_surfaces_egl_device (CoglOnscreen *onscreen, } #endif /* HAVE_EGL_DEVICE */ +static void +on_view_color_state_changed (ClutterStageView *stage_view, + GParamSpec *pspec, + MetaOnscreenNative *onscreen_native) +{ + MetaCrtcKms *crtc_kms; + MetaKmsCrtc *kms_crtc; + + if (!g_str_equal (pspec->name, "color-state") && + !g_str_equal (pspec->name, "output-color-state")) + return; + + if (!META_IS_CRTC_KMS (onscreen_native->crtc)) + return; + + crtc_kms = META_CRTC_KMS (onscreen_native->crtc); + kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); + + if (!meta_kms_crtc_has_color_pipeline (kms_crtc)) + return; + + onscreen_native->property.color_pipeline.invalidated = TRUE; + clutter_stage_view_schedule_update (stage_view); +} + void meta_onscreen_native_set_view (CoglOnscreen *onscreen, MetaRendererView *view) { MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); onscreen_native->view = view; + + if (view && META_IS_CRTC_KMS (onscreen_native->crtc)) + { + MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc); + MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); + + if (meta_kms_crtc_has_color_pipeline (kms_crtc)) + { + ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view); + + onscreen_native->property.color_pipeline.signal_handler_id = + g_signal_connect (stage_view, "notify", + G_CALLBACK (on_view_color_state_changed), + onscreen_native); + } + } } static gboolean @@ -3430,6 +3717,18 @@ meta_onscreen_native_invalidate (MetaOnscreenNative *onscreen_native) onscreen_native->property.gamma_lut.invalidated = TRUE; if (output_info->supports_privacy_screen) onscreen_native->property.privacy_screen.invalidated = TRUE; + + if (META_IS_CRTC_KMS (onscreen_native->crtc)) + { + MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc); + MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); + + if (meta_kms_crtc_has_color_pipeline (kms_crtc)) + onscreen_native->property.color_pipeline.invalidated = TRUE; + } + + if (onscreen_native->view) + clutter_stage_view_schedule_update (CLUTTER_STAGE_VIEW (onscreen_native->view)); } static void @@ -3500,6 +3799,15 @@ meta_onscreen_native_new (MetaRendererNative *renderer_native, onscreen_native); } + if (META_IS_CRTC_KMS (crtc)) + { + MetaCrtcKms *new_crtc_kms = META_CRTC_KMS (crtc); + MetaKmsCrtc *new_kms_crtc = meta_crtc_kms_get_kms_crtc (new_crtc_kms); + + if (meta_kms_crtc_has_color_pipeline (new_kms_crtc)) + onscreen_native->property.color_pipeline.invalidated = TRUE; + } + return onscreen_native; } @@ -3510,6 +3818,11 @@ clear_invalidation_handlers (MetaOnscreenNative *onscreen_native) onscreen_native->crtc); g_clear_signal_handler (&onscreen_native->property.privacy_screen.signal_handler_id, onscreen_native->output); + if (onscreen_native->view) + { + g_clear_signal_handler (&onscreen_native->property.color_pipeline.signal_handler_id, + CLUTTER_STAGE_VIEW (onscreen_native->view)); + } } static void -- GitLab