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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3535>
This commit is contained in:
Sebastian Wick 2024-01-17 13:22:56 +01:00 committed by Marge Bot
parent d45104c14a
commit c4399bd94d
8 changed files with 170 additions and 2 deletions

View File

@ -40,6 +40,14 @@ typedef enum
META_OUTPUT_HDR_METADATA_EOTF_HLG, META_OUTPUT_HDR_METADATA_EOTF_HLG,
} MetaOutputHdrMetadataEOTF; } 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 typedef struct _MetaOutputHdrMetadata
{ {
gboolean active; gboolean active;

View File

@ -39,6 +39,7 @@ typedef enum _MetaKmsConnectorProp
META_KMS_CONNECTOR_PROP_MAX_BPC, META_KMS_CONNECTOR_PROP_MAX_BPC,
META_KMS_CONNECTOR_PROP_COLORSPACE, META_KMS_CONNECTOR_PROP_COLORSPACE,
META_KMS_CONNECTOR_PROP_HDR_OUTPUT_METADATA, META_KMS_CONNECTOR_PROP_HDR_OUTPUT_METADATA,
META_KMS_CONNECTOR_PROP_BROADCAST_RGB,
META_KMS_CONNECTOR_N_PROPS META_KMS_CONNECTOR_N_PROPS
} MetaKmsConnectorProp; } MetaKmsConnectorProp;
@ -113,6 +114,15 @@ typedef enum _MetaKmsConnectorColorspace
META_KMS_CONNECTOR_COLORSPACE_UNKNOWN, META_KMS_CONNECTOR_COLORSPACE_UNKNOWN,
} MetaKmsConnectorColorspace; } 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, uint32_t meta_kms_connector_get_prop_id (MetaKmsConnector *connector,
MetaKmsConnectorProp prop); 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_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 META_EXPORT_TEST
void meta_set_drm_hdr_metadata (MetaOutputHdrMetadata *metadata, void meta_set_drm_hdr_metadata (MetaOutputHdrMetadata *metadata,
struct hdr_output_metadata *drm_metadata); struct hdr_output_metadata *drm_metadata);

View File

@ -56,6 +56,7 @@ typedef struct _MetaKmsConnectorPropTable
MetaKmsEnum scaling_mode_enum[META_KMS_CONNECTOR_SCALING_MODE_N_PROPS]; MetaKmsEnum scaling_mode_enum[META_KMS_CONNECTOR_SCALING_MODE_N_PROPS];
MetaKmsEnum panel_orientation_enum[META_KMS_CONNECTOR_PANEL_ORIENTATION_N_PROPS]; MetaKmsEnum panel_orientation_enum[META_KMS_CONNECTOR_PANEL_ORIENTATION_N_PROPS];
MetaKmsEnum colorspace_enum[META_KMS_CONNECTOR_COLORSPACE_N_PROPS]; MetaKmsEnum colorspace_enum[META_KMS_CONNECTOR_COLORSPACE_N_PROPS];
MetaKmsEnum broadcast_rgb_enum[META_KMS_CONNECTOR_BROADCAST_RGB_N_PROPS];
} MetaKmsConnectorPropTable; } MetaKmsConnectorPropTable;
struct _MetaKmsConnector struct _MetaKmsConnector
@ -253,6 +254,13 @@ meta_kms_connector_is_hdr_metadata_supported (MetaKmsConnector *connector)
return connector->current_state->hdr.supported; 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 static void
set_panel_orientation (MetaKmsConnectorState *state, set_panel_orientation (MetaKmsConnectorState *state,
MetaKmsProp *panel_orientation) 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 static void
state_set_properties (MetaKmsConnectorState *state, state_set_properties (MetaKmsConnectorState *state,
MetaKmsImplDevice *impl_device, MetaKmsImplDevice *impl_device,
@ -408,6 +463,15 @@ state_set_properties (MetaKmsConnectorState *state,
state->colorspace.supported = state->colorspace.supported =
supported_drm_color_spaces_to_output_color_spaces (prop->supported_variants); 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 static CoglSubpixelOrder
@ -1013,6 +1077,10 @@ meta_kms_connector_state_changes (MetaKmsConnectorState *state,
!hdr_metadata_equal (&state->hdr.value, &new_state->hdr.value)) !hdr_metadata_equal (&state->hdr.value, &new_state->hdr.value))
return META_KMS_RESOURCE_CHANGE_FULL; 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) if (state->privacy_screen_state != new_state->privacy_screen_state)
return META_KMS_RESOURCE_CHANGE_PRIVACY_SCREEN; return META_KMS_RESOURCE_CHANGE_PRIVACY_SCREEN;
@ -1224,6 +1292,14 @@ meta_kms_connector_predict_state_in_impl (MetaKmsConnector *connector,
connector)); connector));
current_state->hdr.value = connector_update->hdr.value; 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); sync_fd_held (connector, connector->impl_device);
@ -1350,6 +1426,14 @@ init_properties (MetaKmsConnector *connector,
.name = "HDR_OUTPUT_METADATA", .name = "HDR_OUTPUT_METADATA",
.type = DRM_MODE_PROP_BLOB, .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 = { .dpms_enum = {
[META_KMS_CONNECTOR_DPMS_ON] = [META_KMS_CONNECTOR_DPMS_ON] =
@ -1521,6 +1605,20 @@ init_properties (MetaKmsConnector *connector,
.name = "DCI-P3_RGB_Theater", .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",
}
},
}; };
} }

View File

@ -69,6 +69,11 @@ typedef struct _MetaKmsConnectorState
gboolean supported; gboolean supported;
gboolean unknown; gboolean unknown;
} hdr; } hdr;
struct {
MetaOutputRGBRange value;
uint64_t supported;
} broadcast_rgb;
} MetaKmsConnectorState; } MetaKmsConnectorState;
META_EXPORT_TEST 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, gboolean meta_kms_connector_is_color_space_supported (MetaKmsConnector *connector,
MetaOutputColorspace color_space); 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); gboolean meta_kms_connector_is_hdr_metadata_supported (MetaKmsConnector *connector);

View File

@ -292,6 +292,25 @@ process_connector_update (MetaKmsImplDevice *impl_device,
return FALSE; 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; return TRUE;
} }

View File

@ -110,6 +110,11 @@ typedef struct _MetaKmsConnectorUpdate
gboolean has_update; gboolean has_update;
MetaOutputHdrMetadata value; MetaOutputHdrMetadata value;
} hdr; } hdr;
struct {
gboolean has_update;
MetaOutputRGBRange value;
} broadcast_rgb;
} MetaKmsConnectorUpdate; } MetaKmsConnectorUpdate;
typedef struct _MetaKmsPageFlipListener typedef struct _MetaKmsPageFlipListener

View File

@ -444,8 +444,6 @@ meta_kms_update_set_color_space (MetaKmsUpdate *update,
MetaKmsConnectorUpdate *connector_update; MetaKmsConnectorUpdate *connector_update;
g_assert (meta_kms_connector_get_device (connector) == update->device); 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 = ensure_connector_update (update, connector);
connector_update->colorspace.has_update = TRUE; connector_update->colorspace.has_update = TRUE;
@ -470,6 +468,22 @@ meta_kms_update_set_hdr_metadata (MetaKmsUpdate *update,
update->needs_modeset = TRUE; 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 * static MetaKmsCrtcColorUpdate *
ensure_color_update (MetaKmsUpdate *update, ensure_color_update (MetaKmsUpdate *update,
MetaKmsCrtc *crtc) MetaKmsCrtc *crtc)

View File

@ -134,6 +134,10 @@ void meta_kms_update_set_hdr_metadata (MetaKmsUpdate *update,
MetaKmsConnector *connector, MetaKmsConnector *connector,
MetaOutputHdrMetadata *metadata); MetaOutputHdrMetadata *metadata);
void meta_kms_update_set_broadcast_rgb (MetaKmsUpdate *update,
MetaKmsConnector *connector,
MetaOutputRGBRange rgb_range);
META_EXPORT_TEST META_EXPORT_TEST
void meta_kms_update_set_power_save (MetaKmsUpdate *update); void meta_kms_update_set_power_save (MetaKmsUpdate *update);