backends/native: Read color space and HDR metadata connector state
The HDR Static Metadata InfoFrame contents are described in CTA-861.3 and the kernel maintains a representation of that in `struct hdr_metadata_infoframe` in `include/uapi/drm/drm_mode.h`. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2879>
This commit is contained in:
parent
2e69eafa06
commit
76e69f2375
@ -31,6 +31,23 @@
|
|||||||
#include "backends/native/meta-kms-mode-private.h"
|
#include "backends/native/meta-kms-mode-private.h"
|
||||||
#include "backends/native/meta-kms-update-private.h"
|
#include "backends/native/meta-kms-update-private.h"
|
||||||
|
|
||||||
|
/* CTA-861.3 HDR Static Metadata Extension, Table 3,
|
||||||
|
* Electro-Optical Transfer Function */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
HDR_METADATA_EOTF_TRADITIONAL_GAMMA_SDR = 0,
|
||||||
|
HDR_METADATA_EOTF_TRADITIONAL_GAMMA_HDR = 1,
|
||||||
|
HDR_METADATA_EOTF_PERCEPTUAL_QUANTIZER = 2,
|
||||||
|
HDR_METADATA_EOTF_HYBRID_LOG_GAMMA = 3,
|
||||||
|
} HdrMetadataEotf;
|
||||||
|
|
||||||
|
/* CTA-861.3 HDR Static Metadata Extension, Table 4,
|
||||||
|
* Static_Metadata_Descriptor_ID */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
HDR_STATIC_METADATA_TYPE_1 = 0,
|
||||||
|
} HdrStaticMetadataType;
|
||||||
|
|
||||||
typedef struct _MetaKmsConnectorPropTable
|
typedef struct _MetaKmsConnectorPropTable
|
||||||
{
|
{
|
||||||
MetaKmsProp props[META_KMS_CONNECTOR_N_PROPS];
|
MetaKmsProp props[META_KMS_CONNECTOR_N_PROPS];
|
||||||
@ -225,6 +242,19 @@ sync_fd_held (MetaKmsConnector *connector,
|
|||||||
connector->fd_held = should_hold_fd;
|
connector->fd_held = should_hold_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_kms_connector_is_color_space_supported (MetaKmsConnector *connector,
|
||||||
|
MetaOutputColorspace color_space)
|
||||||
|
{
|
||||||
|
return !!(connector->current_state->colorspace.supported & (1 << color_space));
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_kms_connector_is_hdr_metadata_supported (MetaKmsConnector *connector)
|
||||||
|
{
|
||||||
|
return connector->current_state->hdr.supported;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_panel_orientation (MetaKmsConnectorState *state,
|
set_panel_orientation (MetaKmsConnectorState *state,
|
||||||
MetaKmsProp *panel_orientation)
|
MetaKmsProp *panel_orientation)
|
||||||
@ -286,6 +316,33 @@ set_privacy_screen (MetaKmsConnectorState *state,
|
|||||||
state->privacy_screen_state |= META_PRIVACY_SCREEN_LOCKED;
|
state->privacy_screen_state |= META_PRIVACY_SCREEN_LOCKED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MetaOutputColorspace
|
||||||
|
drm_color_spaces_to_output_color_spaces (uint64_t drm_color_space)
|
||||||
|
{
|
||||||
|
switch (drm_color_space)
|
||||||
|
{
|
||||||
|
case META_KMS_CONNECTOR_COLORSPACE_DEFAULT:
|
||||||
|
return META_OUTPUT_COLORSPACE_DEFAULT;
|
||||||
|
case META_KMS_CONNECTOR_COLORSPACE_BT2020_RGB:
|
||||||
|
return META_OUTPUT_COLORSPACE_BT2020;
|
||||||
|
default:
|
||||||
|
return META_OUTPUT_COLORSPACE_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
supported_drm_color_spaces_to_output_color_spaces (uint64_t drm_support)
|
||||||
|
{
|
||||||
|
uint64_t supported = 0;
|
||||||
|
|
||||||
|
if (drm_support & (1 << META_KMS_CONNECTOR_COLORSPACE_DEFAULT))
|
||||||
|
supported |= (1 << META_OUTPUT_COLORSPACE_DEFAULT);
|
||||||
|
if (drm_support & (1 << META_KMS_CONNECTOR_COLORSPACE_BT2020_RGB))
|
||||||
|
supported |= (1 << META_OUTPUT_COLORSPACE_BT2020);
|
||||||
|
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
state_set_properties (MetaKmsConnectorState *state,
|
state_set_properties (MetaKmsConnectorState *state,
|
||||||
MetaKmsImplDevice *impl_device,
|
MetaKmsImplDevice *impl_device,
|
||||||
@ -330,6 +387,15 @@ state_set_properties (MetaKmsConnectorState *state,
|
|||||||
state->max_bpc.min_value = prop->range_min;
|
state->max_bpc.min_value = prop->range_min;
|
||||||
state->max_bpc.max_value = prop->range_max;
|
state->max_bpc.max_value = prop->range_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prop = &props[META_KMS_CONNECTOR_PROP_COLORSPACE];
|
||||||
|
if (prop->prop_id)
|
||||||
|
{
|
||||||
|
state->colorspace.value =
|
||||||
|
drm_color_spaces_to_output_color_spaces (prop->value);
|
||||||
|
state->colorspace.supported =
|
||||||
|
supported_drm_color_spaces_to_output_color_spaces (prop->supported_variants);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CoglSubpixelOrder
|
static CoglSubpixelOrder
|
||||||
@ -424,21 +490,146 @@ state_set_tile_info (MetaKmsConnectorState *state,
|
|||||||
drmModeFreePropertyBlob (tile_blob);
|
drmModeFreePropertyBlob (tile_blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
decode_u16_chromaticity (uint16_t value)
|
||||||
|
{
|
||||||
|
/* CTA-861.3 HDR Static Metadata Extension, 3.2.1 Static Metadata Type 1 */
|
||||||
|
return MIN (value * 0.00002, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
decode_u16_min_luminance (uint16_t value)
|
||||||
|
{
|
||||||
|
/* CTA-861.3 HDR Static Metadata Extension, 3.2.1 Static Metadata Type 1 */
|
||||||
|
return value * 0.0001;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
set_output_hdr_metadata (struct hdr_output_metadata *drm_metadata,
|
||||||
|
MetaOutputHdrMetadata *metadata)
|
||||||
|
{
|
||||||
|
struct hdr_metadata_infoframe *infoframe;
|
||||||
|
|
||||||
|
if (drm_metadata->metadata_type != HDR_STATIC_METADATA_TYPE_1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
infoframe = &drm_metadata->hdmi_metadata_type1;
|
||||||
|
|
||||||
|
if (infoframe->metadata_type != HDR_STATIC_METADATA_TYPE_1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch (infoframe->eotf)
|
||||||
|
{
|
||||||
|
case HDR_METADATA_EOTF_TRADITIONAL_GAMMA_SDR:
|
||||||
|
metadata->eotf = META_OUTPUT_HDR_METADATA_EOTF_TRADITIONAL_GAMMA_SDR;
|
||||||
|
break;
|
||||||
|
case HDR_METADATA_EOTF_TRADITIONAL_GAMMA_HDR:
|
||||||
|
metadata->eotf = META_OUTPUT_HDR_METADATA_EOTF_TRADITIONAL_GAMMA_HDR;
|
||||||
|
break;
|
||||||
|
case HDR_METADATA_EOTF_PERCEPTUAL_QUANTIZER:
|
||||||
|
metadata->eotf = META_OUTPUT_HDR_METADATA_EOTF_PQ;
|
||||||
|
break;
|
||||||
|
case HDR_METADATA_EOTF_HYBRID_LOG_GAMMA:
|
||||||
|
metadata->eotf = META_OUTPUT_HDR_METADATA_EOTF_HLG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CTA-861.3 HDR Static Metadata Extension, 3.2.1 Static Metadata Type 1 */
|
||||||
|
metadata->mastering_display_primaries[0].x =
|
||||||
|
decode_u16_chromaticity (infoframe->display_primaries[0].x);
|
||||||
|
metadata->mastering_display_primaries[0].y =
|
||||||
|
decode_u16_chromaticity (infoframe->display_primaries[0].y);
|
||||||
|
metadata->mastering_display_primaries[1].x =
|
||||||
|
decode_u16_chromaticity (infoframe->display_primaries[1].x);
|
||||||
|
metadata->mastering_display_primaries[1].y =
|
||||||
|
decode_u16_chromaticity (infoframe->display_primaries[1].y);
|
||||||
|
metadata->mastering_display_primaries[2].x =
|
||||||
|
decode_u16_chromaticity (infoframe->display_primaries[2].x);
|
||||||
|
metadata->mastering_display_primaries[2].y =
|
||||||
|
decode_u16_chromaticity (infoframe->display_primaries[2].y);
|
||||||
|
metadata->mastering_display_white_point.x =
|
||||||
|
decode_u16_chromaticity (infoframe->white_point.x);
|
||||||
|
metadata->mastering_display_white_point.y =
|
||||||
|
decode_u16_chromaticity (infoframe->white_point.y);
|
||||||
|
|
||||||
|
metadata->mastering_display_max_luminance =
|
||||||
|
infoframe->max_display_mastering_luminance;
|
||||||
|
metadata->mastering_display_min_luminance =
|
||||||
|
decode_u16_min_luminance (infoframe->min_display_mastering_luminance);
|
||||||
|
|
||||||
|
metadata->max_cll = infoframe->max_cll;
|
||||||
|
metadata->max_fall = infoframe->max_fall;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
state_set_hdr_output_metadata (MetaKmsConnectorState *state,
|
||||||
|
MetaKmsConnector *connector,
|
||||||
|
MetaKmsImplDevice *impl_device,
|
||||||
|
uint32_t blob_id)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
drmModePropertyBlobPtr hdr_blob;
|
||||||
|
MetaOutputHdrMetadata *metadata = &state->hdr.value;
|
||||||
|
struct hdr_output_metadata *drm_metadata;
|
||||||
|
|
||||||
|
state->hdr.supported = TRUE;
|
||||||
|
state->hdr.unknown = FALSE;
|
||||||
|
metadata->active = TRUE;
|
||||||
|
|
||||||
|
if (!blob_id)
|
||||||
|
{
|
||||||
|
metadata->active = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = meta_kms_impl_device_get_fd (impl_device);
|
||||||
|
hdr_blob = drmModeGetPropertyBlob (fd, blob_id);
|
||||||
|
if (!hdr_blob)
|
||||||
|
{
|
||||||
|
metadata->active = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr_blob->length < sizeof (*drm_metadata))
|
||||||
|
{
|
||||||
|
g_warning ("HDR_OUTPUT_METADATA smaller than expected for type 1");
|
||||||
|
state->hdr.unknown = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_metadata = hdr_blob->data;
|
||||||
|
if (!set_output_hdr_metadata (drm_metadata, metadata))
|
||||||
|
{
|
||||||
|
state->hdr.unknown = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
drmModeFreePropertyBlob (hdr_blob);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
state_set_blobs (MetaKmsConnectorState *state,
|
state_set_blobs (MetaKmsConnectorState *state,
|
||||||
MetaKmsConnector *connector,
|
MetaKmsConnector *connector,
|
||||||
MetaKmsImplDevice *impl_device,
|
MetaKmsImplDevice *impl_device,
|
||||||
drmModeConnector *drm_connector)
|
drmModeConnector *drm_connector)
|
||||||
{
|
{
|
||||||
|
MetaKmsProp *props = connector->prop_table.props;
|
||||||
MetaKmsProp *prop;
|
MetaKmsProp *prop;
|
||||||
|
|
||||||
prop = &connector->prop_table.props[META_KMS_CONNECTOR_PROP_EDID];
|
prop = &props[META_KMS_CONNECTOR_PROP_EDID];
|
||||||
if (prop->prop_id && prop->value)
|
if (prop->prop_id && prop->value)
|
||||||
state_set_edid (state, connector, impl_device, prop->value);
|
state_set_edid (state, connector, impl_device, prop->value);
|
||||||
|
|
||||||
prop = &connector->prop_table.props[META_KMS_CONNECTOR_PROP_TILE];
|
prop = &props[META_KMS_CONNECTOR_PROP_TILE];
|
||||||
if (prop->prop_id && prop->value)
|
if (prop->prop_id && prop->value)
|
||||||
state_set_tile_info (state, connector, impl_device, prop->value);
|
state_set_tile_info (state, connector, impl_device, prop->value);
|
||||||
|
|
||||||
|
prop = &props[META_KMS_CONNECTOR_PROP_HDR_OUTPUT_METADATA];
|
||||||
|
if (prop->prop_id)
|
||||||
|
state_set_hdr_output_metadata (state, connector, impl_device, prop->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -590,6 +781,70 @@ kms_modes_equal (GList *modes,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
hdr_primaries_equal (double x1, double x2)
|
||||||
|
{
|
||||||
|
return fabs (x1 - x2) < (0.00002 - DBL_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
hdr_nits_equal (double x1, double x2)
|
||||||
|
{
|
||||||
|
return fabs (x1 - x2) < (1.0 - DBL_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
hdr_min_luminance_equal (double x1, double x2)
|
||||||
|
{
|
||||||
|
return fabs (x1 - x2) < (0.0001 - DBL_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
hdr_metadata_equal (MetaOutputHdrMetadata *metadata,
|
||||||
|
MetaOutputHdrMetadata *other_metadata)
|
||||||
|
{
|
||||||
|
if (!metadata->active && !other_metadata->active)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (metadata->active != other_metadata->active)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (metadata->eotf != other_metadata->eotf)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!hdr_primaries_equal (metadata->mastering_display_primaries[0].x,
|
||||||
|
other_metadata->mastering_display_primaries[0].x) ||
|
||||||
|
!hdr_primaries_equal (metadata->mastering_display_primaries[0].y,
|
||||||
|
other_metadata->mastering_display_primaries[0].y) ||
|
||||||
|
!hdr_primaries_equal (metadata->mastering_display_primaries[1].x,
|
||||||
|
other_metadata->mastering_display_primaries[1].x) ||
|
||||||
|
!hdr_primaries_equal (metadata->mastering_display_primaries[1].y,
|
||||||
|
other_metadata->mastering_display_primaries[1].y) ||
|
||||||
|
!hdr_primaries_equal (metadata->mastering_display_primaries[2].x,
|
||||||
|
other_metadata->mastering_display_primaries[2].x) ||
|
||||||
|
!hdr_primaries_equal (metadata->mastering_display_primaries[2].y,
|
||||||
|
other_metadata->mastering_display_primaries[2].y) ||
|
||||||
|
!hdr_primaries_equal (metadata->mastering_display_white_point.x,
|
||||||
|
other_metadata->mastering_display_white_point.x) ||
|
||||||
|
!hdr_primaries_equal (metadata->mastering_display_white_point.y,
|
||||||
|
other_metadata->mastering_display_white_point.y))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!hdr_nits_equal (metadata->mastering_display_max_luminance,
|
||||||
|
other_metadata->mastering_display_max_luminance))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!hdr_min_luminance_equal (metadata->mastering_display_min_luminance,
|
||||||
|
other_metadata->mastering_display_min_luminance))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!hdr_nits_equal (metadata->max_cll, other_metadata->max_cll) ||
|
||||||
|
!hdr_nits_equal (metadata->max_fall, other_metadata->max_fall))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static MetaKmsResourceChanges
|
static MetaKmsResourceChanges
|
||||||
meta_kms_connector_state_changes (MetaKmsConnectorState *state,
|
meta_kms_connector_state_changes (MetaKmsConnectorState *state,
|
||||||
MetaKmsConnectorState *new_state)
|
MetaKmsConnectorState *new_state)
|
||||||
@ -649,6 +904,15 @@ meta_kms_connector_state_changes (MetaKmsConnectorState *state,
|
|||||||
state->max_bpc.max_value != new_state->max_bpc.max_value)
|
state->max_bpc.max_value != new_state->max_bpc.max_value)
|
||||||
return META_KMS_RESOURCE_CHANGE_FULL;
|
return META_KMS_RESOURCE_CHANGE_FULL;
|
||||||
|
|
||||||
|
if (state->colorspace.value != new_state->colorspace.value ||
|
||||||
|
state->colorspace.supported != new_state->colorspace.supported)
|
||||||
|
return META_KMS_RESOURCE_CHANGE_FULL;
|
||||||
|
|
||||||
|
if (state->hdr.supported != new_state->hdr.supported ||
|
||||||
|
state->hdr.unknown != new_state->hdr.unknown ||
|
||||||
|
!hdr_metadata_equal (&state->hdr.value, &new_state->hdr.value))
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -61,6 +61,17 @@ typedef struct _MetaKmsConnectorState
|
|||||||
MetaMonitorTransform panel_orientation_transform;
|
MetaMonitorTransform panel_orientation_transform;
|
||||||
|
|
||||||
MetaKmsRange max_bpc;
|
MetaKmsRange max_bpc;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
MetaOutputColorspace value;
|
||||||
|
uint64_t supported;
|
||||||
|
} colorspace;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
MetaOutputHdrMetadata value;
|
||||||
|
gboolean supported;
|
||||||
|
gboolean unknown;
|
||||||
|
} hdr;
|
||||||
} MetaKmsConnectorState;
|
} MetaKmsConnectorState;
|
||||||
|
|
||||||
META_EXPORT_TEST
|
META_EXPORT_TEST
|
||||||
@ -87,4 +98,9 @@ gboolean meta_kms_connector_is_privacy_screen_supported (MetaKmsConnector *conne
|
|||||||
|
|
||||||
const MetaKmsRange * meta_kms_connector_get_max_bpc (MetaKmsConnector *connector);
|
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_hdr_metadata_supported (MetaKmsConnector *connector);
|
||||||
|
|
||||||
#endif /* META_KMS_CONNECTOR_H */
|
#endif /* META_KMS_CONNECTOR_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user