From c4399bd94d5e88f4571e43172e66c9943e1a6461 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 17 Jan 2024 13:22:56 +0100 Subject: [PATCH] kms/connector: Add support for the Broadcast RGB property It can be used to force a specific RGB range. Some monitors don't follow the specification and expect a signal different from what we send. This property allows to force a mode which hopefully then works correctly for the sink. Part-of: --- src/backends/meta-output.h | 8 ++ .../native/meta-kms-connector-private.h | 12 +++ src/backends/native/meta-kms-connector.c | 98 +++++++++++++++++++ src/backends/native/meta-kms-connector.h | 8 ++ .../native/meta-kms-impl-device-atomic.c | 19 ++++ src/backends/native/meta-kms-update-private.h | 5 + src/backends/native/meta-kms-update.c | 18 +++- src/backends/native/meta-kms-update.h | 4 + 8 files changed, 170 insertions(+), 2 deletions(-) diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h index 03a4cc385..79cde47af 100644 --- a/src/backends/meta-output.h +++ b/src/backends/meta-output.h @@ -40,6 +40,14 @@ typedef enum META_OUTPUT_HDR_METADATA_EOTF_HLG, } MetaOutputHdrMetadataEOTF; +typedef enum _MetaOutputRGBRange +{ + META_OUTPUT_RGB_RANGE_UNKNOWN = 0, + META_OUTPUT_RGB_RANGE_AUTO, + META_OUTPUT_RGB_RANGE_FULL, + META_OUTPUT_RGB_RANGE_LIMITED, +} MetaOutputRGBRange; + typedef struct _MetaOutputHdrMetadata { gboolean active; diff --git a/src/backends/native/meta-kms-connector-private.h b/src/backends/native/meta-kms-connector-private.h index 1f8446f5f..8be080dfb 100644 --- a/src/backends/native/meta-kms-connector-private.h +++ b/src/backends/native/meta-kms-connector-private.h @@ -39,6 +39,7 @@ typedef enum _MetaKmsConnectorProp META_KMS_CONNECTOR_PROP_MAX_BPC, META_KMS_CONNECTOR_PROP_COLORSPACE, META_KMS_CONNECTOR_PROP_HDR_OUTPUT_METADATA, + META_KMS_CONNECTOR_PROP_BROADCAST_RGB, META_KMS_CONNECTOR_N_PROPS } MetaKmsConnectorProp; @@ -113,6 +114,15 @@ typedef enum _MetaKmsConnectorColorspace META_KMS_CONNECTOR_COLORSPACE_UNKNOWN, } MetaKmsConnectorColorspace; +typedef enum _MetaKmsConnectorBroadcastRGB +{ + META_KMS_CONNECTOR_BROADCAST_RGB_AUTOMATIC = 0, + META_KMS_CONNECTOR_BROADCAST_RGB_FULL, + META_KMS_CONNECTOR_BROADCAST_RGB_LIMITED_16_235, + META_KMS_CONNECTOR_BROADCAST_RGB_N_PROPS, + META_KMS_CONNECTOR_BROADCAST_RGB_UNKNOWN, +} MetaKmsConnectorBroadcastRGB; + uint32_t meta_kms_connector_get_prop_id (MetaKmsConnector *connector, MetaKmsConnectorProp prop); @@ -141,6 +151,8 @@ gboolean meta_kms_connector_is_same_as (MetaKmsConnector *connector, uint64_t meta_output_color_space_to_drm_color_space (MetaOutputColorspace color_space); +uint64_t meta_output_rgb_range_to_drm_broadcast_rgb (MetaOutputRGBRange rgb_range); + META_EXPORT_TEST void meta_set_drm_hdr_metadata (MetaOutputHdrMetadata *metadata, struct hdr_output_metadata *drm_metadata); diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index 9acf4aa55..1ff274f1e 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -56,6 +56,7 @@ typedef struct _MetaKmsConnectorPropTable MetaKmsEnum scaling_mode_enum[META_KMS_CONNECTOR_SCALING_MODE_N_PROPS]; MetaKmsEnum panel_orientation_enum[META_KMS_CONNECTOR_PANEL_ORIENTATION_N_PROPS]; MetaKmsEnum colorspace_enum[META_KMS_CONNECTOR_COLORSPACE_N_PROPS]; + MetaKmsEnum broadcast_rgb_enum[META_KMS_CONNECTOR_BROADCAST_RGB_N_PROPS]; } MetaKmsConnectorPropTable; struct _MetaKmsConnector @@ -253,6 +254,13 @@ meta_kms_connector_is_hdr_metadata_supported (MetaKmsConnector *connector) return connector->current_state->hdr.supported; } +gboolean +meta_kms_connector_is_broadcast_rgb_supported (MetaKmsConnector *connector, + MetaOutputRGBRange broadcast_rgb) +{ + return !!(connector->current_state->broadcast_rgb.supported & (1 << broadcast_rgb)); +} + static void set_panel_orientation (MetaKmsConnectorState *state, MetaKmsProp *panel_orientation) @@ -355,6 +363,53 @@ meta_output_color_space_to_drm_color_space (MetaOutputColorspace color_space) } } +static MetaOutputRGBRange +drm_broadcast_rgb_to_output_rgb_range (uint64_t drm_broadcast_rgb) +{ + switch (drm_broadcast_rgb) + { + case META_KMS_CONNECTOR_BROADCAST_RGB_AUTOMATIC: + return META_OUTPUT_RGB_RANGE_AUTO; + case META_KMS_CONNECTOR_BROADCAST_RGB_FULL: + return META_OUTPUT_RGB_RANGE_FULL; + case META_KMS_CONNECTOR_BROADCAST_RGB_LIMITED_16_235: + return META_OUTPUT_RGB_RANGE_LIMITED; + default: + return META_OUTPUT_RGB_RANGE_UNKNOWN; + } +} + +static uint64_t +supported_drm_broadcast_rgb_to_output_rgb_range (uint64_t drm_support) +{ + uint64_t supported = 0; + + if (drm_support & (1 << META_KMS_CONNECTOR_BROADCAST_RGB_AUTOMATIC)) + supported |= (1 << META_OUTPUT_RGB_RANGE_AUTO); + if (drm_support & (1 << META_KMS_CONNECTOR_BROADCAST_RGB_FULL)) + supported |= (1 << META_OUTPUT_RGB_RANGE_FULL); + if (drm_support & (1 << META_KMS_CONNECTOR_BROADCAST_RGB_LIMITED_16_235)) + supported |= (1 << META_OUTPUT_RGB_RANGE_LIMITED); + + return supported; +} + +uint64_t +meta_output_rgb_range_to_drm_broadcast_rgb (MetaOutputRGBRange rgb_range) +{ + switch (rgb_range) + { + case META_OUTPUT_RGB_RANGE_FULL: + return META_KMS_CONNECTOR_BROADCAST_RGB_FULL; + case META_OUTPUT_RGB_RANGE_LIMITED: + return META_KMS_CONNECTOR_BROADCAST_RGB_LIMITED_16_235; + case META_OUTPUT_RGB_RANGE_UNKNOWN: + case META_OUTPUT_RGB_RANGE_AUTO: + default: + return META_KMS_CONNECTOR_BROADCAST_RGB_AUTOMATIC; + } +} + static void state_set_properties (MetaKmsConnectorState *state, MetaKmsImplDevice *impl_device, @@ -408,6 +463,15 @@ state_set_properties (MetaKmsConnectorState *state, state->colorspace.supported = supported_drm_color_spaces_to_output_color_spaces (prop->supported_variants); } + + prop = &props[META_KMS_CONNECTOR_PROP_BROADCAST_RGB]; + if (prop->prop_id) + { + state->broadcast_rgb.value = + drm_broadcast_rgb_to_output_rgb_range (prop->value); + state->broadcast_rgb.supported = + supported_drm_broadcast_rgb_to_output_rgb_range (prop->supported_variants); + } } static CoglSubpixelOrder @@ -1013,6 +1077,10 @@ meta_kms_connector_state_changes (MetaKmsConnectorState *state, !hdr_metadata_equal (&state->hdr.value, &new_state->hdr.value)) return META_KMS_RESOURCE_CHANGE_FULL; + if (state->broadcast_rgb.value != new_state->broadcast_rgb.value || + state->broadcast_rgb.supported != new_state->broadcast_rgb.supported) + return META_KMS_RESOURCE_CHANGE_FULL; + if (state->privacy_screen_state != new_state->privacy_screen_state) return META_KMS_RESOURCE_CHANGE_PRIVACY_SCREEN; @@ -1224,6 +1292,14 @@ meta_kms_connector_predict_state_in_impl (MetaKmsConnector *connector, connector)); current_state->hdr.value = connector_update->hdr.value; } + + if (connector_update->broadcast_rgb.has_update) + { + g_warn_if_fail (meta_kms_connector_is_broadcast_rgb_supported ( + connector, + connector_update->broadcast_rgb.value)); + current_state->broadcast_rgb.value = connector_update->broadcast_rgb.value; + } } sync_fd_held (connector, connector->impl_device); @@ -1350,6 +1426,14 @@ init_properties (MetaKmsConnector *connector, .name = "HDR_OUTPUT_METADATA", .type = DRM_MODE_PROP_BLOB, }, + [META_KMS_CONNECTOR_PROP_BROADCAST_RGB] = + { + .name = "Broadcast RGB", + .type = DRM_MODE_PROP_ENUM, + .enum_values = prop_table->broadcast_rgb_enum, + .num_enum_values = META_KMS_CONNECTOR_BROADCAST_RGB_N_PROPS, + .default_value = META_KMS_CONNECTOR_BROADCAST_RGB_UNKNOWN, + }, }, .dpms_enum = { [META_KMS_CONNECTOR_DPMS_ON] = @@ -1521,6 +1605,20 @@ init_properties (MetaKmsConnector *connector, .name = "DCI-P3_RGB_Theater", }, }, + .broadcast_rgb_enum = { + [META_KMS_CONNECTOR_BROADCAST_RGB_AUTOMATIC] = + { + .name = "Automatic", + }, + [META_KMS_CONNECTOR_BROADCAST_RGB_FULL] = + { + .name = "Full", + }, + [META_KMS_CONNECTOR_BROADCAST_RGB_LIMITED_16_235] = + { + .name = "Limited 16:235", + } + }, }; } diff --git a/src/backends/native/meta-kms-connector.h b/src/backends/native/meta-kms-connector.h index b988672c3..30919d032 100644 --- a/src/backends/native/meta-kms-connector.h +++ b/src/backends/native/meta-kms-connector.h @@ -69,6 +69,11 @@ typedef struct _MetaKmsConnectorState gboolean supported; gboolean unknown; } hdr; + + struct { + MetaOutputRGBRange value; + uint64_t supported; + } broadcast_rgb; } MetaKmsConnectorState; META_EXPORT_TEST @@ -98,4 +103,7 @@ const MetaKmsRange * meta_kms_connector_get_max_bpc (MetaKmsConnector *connector gboolean meta_kms_connector_is_color_space_supported (MetaKmsConnector *connector, MetaOutputColorspace color_space); +gboolean meta_kms_connector_is_broadcast_rgb_supported (MetaKmsConnector *connector, + MetaOutputRGBRange broadcast_rgb); + gboolean meta_kms_connector_is_hdr_metadata_supported (MetaKmsConnector *connector); diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index 5ea36de2a..35837f742 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -292,6 +292,25 @@ process_connector_update (MetaKmsImplDevice *impl_device, return FALSE; } + if (connector_update->broadcast_rgb.has_update) + { + MetaOutputRGBRange rgb_range = connector_update->broadcast_rgb.value; + uint64_t value = meta_output_rgb_range_to_drm_broadcast_rgb (rgb_range); + + meta_topic (META_DEBUG_KMS, + "[atomic] Setting Broadcast RGB to %u on connector %u (%s)", + rgb_range, + meta_kms_connector_get_id (connector), + meta_kms_impl_device_get_path (impl_device)); + + if (!add_connector_property (impl_device, + connector, req, + META_KMS_CONNECTOR_PROP_BROADCAST_RGB, + value, + error)) + return FALSE; + } + return TRUE; } diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index efdd51312..0dfa5ef27 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -110,6 +110,11 @@ typedef struct _MetaKmsConnectorUpdate gboolean has_update; MetaOutputHdrMetadata value; } hdr; + + struct { + gboolean has_update; + MetaOutputRGBRange value; + } broadcast_rgb; } MetaKmsConnectorUpdate; typedef struct _MetaKmsPageFlipListener diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c index 2d4be8096..3eab71b3c 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c @@ -444,8 +444,6 @@ meta_kms_update_set_color_space (MetaKmsUpdate *update, MetaKmsConnectorUpdate *connector_update; g_assert (meta_kms_connector_get_device (connector) == update->device); - g_return_if_fail (meta_kms_connector_is_color_space_supported (connector, - color_space)); connector_update = ensure_connector_update (update, connector); connector_update->colorspace.has_update = TRUE; @@ -470,6 +468,22 @@ meta_kms_update_set_hdr_metadata (MetaKmsUpdate *update, update->needs_modeset = TRUE; } +void +meta_kms_update_set_broadcast_rgb (MetaKmsUpdate *update, + MetaKmsConnector *connector, + MetaOutputRGBRange rgb_range) +{ + MetaKmsConnectorUpdate *connector_update; + + g_assert (meta_kms_connector_get_device (connector) == update->device); + g_return_if_fail (meta_kms_connector_is_broadcast_rgb_supported (connector, + rgb_range)); + + connector_update = ensure_connector_update (update, connector); + connector_update->broadcast_rgb.has_update = TRUE; + connector_update->broadcast_rgb.value = rgb_range; +} + static MetaKmsCrtcColorUpdate * ensure_color_update (MetaKmsUpdate *update, MetaKmsCrtc *crtc) diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h index 7acf2fd48..b6ca3ae01 100644 --- a/src/backends/native/meta-kms-update.h +++ b/src/backends/native/meta-kms-update.h @@ -134,6 +134,10 @@ void meta_kms_update_set_hdr_metadata (MetaKmsUpdate *update, MetaKmsConnector *connector, MetaOutputHdrMetadata *metadata); +void meta_kms_update_set_broadcast_rgb (MetaKmsUpdate *update, + MetaKmsConnector *connector, + MetaOutputRGBRange rgb_range); + META_EXPORT_TEST void meta_kms_update_set_power_save (MetaKmsUpdate *update);