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,
} 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;

View File

@ -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);

View File

@ -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",
}
},
};
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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);