backend-drm: program HDR_OUTPUT_METADATA

Program the connector property HDR_OUTPUT_METADATA based on the EOTF
mode of the output.

For now, this changes only the EOTF. The colorimetry and luminance are
left undefined, to be filled in by later patches. This should still be
enough to put a video sink into HDR mode, albeit the response is
probably unknown.

drm_output keeps track of the currently existing blob id. If the blob
contents need to be re-created, this blob would be destroyed and the
field set to zero. In this patch, there is no provision for runtime
changing of HDR metadata, so there is no code doing that.

Destroying the blob at arbitrary times is not a problem, because the
kernel keeps a reference to the data as long as the blob id remains with
KMS.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
dev
Pekka Paalanen 3 years ago committed by Pekka Paalanen
parent 1d17e4991f
commit 5151f9fe9e
  1. 2
      libweston/backend-drm/drm-internal.h
  2. 77
      libweston/backend-drm/drm.c
  3. 10
      libweston/backend-drm/kms.c
  4. 2
      libweston/backend-drm/modes.c

@ -549,6 +549,8 @@ struct drm_output {
uint32_t gbm_format; uint32_t gbm_format;
uint32_t gbm_bo_flags; uint32_t gbm_bo_flags;
uint32_t hdr_output_metadata_blob_id;
/* Plane being displayed directly on the CRTC */ /* Plane being displayed directly on the CRTC */
struct drm_plane *scanout_plane; struct drm_plane *scanout_plane;

@ -51,6 +51,7 @@
#include <libweston/backend-drm.h> #include <libweston/backend-drm.h>
#include <libweston/weston-log.h> #include <libweston/weston-log.h>
#include "drm-internal.h" #include "drm-internal.h"
#include "libdrm-updates.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/timespec-util.h" #include "shared/timespec-util.h"
#include "shared/string-helpers.h" #include "shared/string-helpers.h"
@ -440,6 +441,71 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
pixman_region32_fini(&scanout_damage); pixman_region32_fini(&scanout_damage);
} }
static int
drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output)
{
struct hdr_output_metadata meta;
uint32_t blob_id = 0;
int ret;
if (output->hdr_output_metadata_blob_id)
return 0;
/*
* Set up the data for Dynamic Range and Mastering InfoFrame,
* CTA-861-G, a.k.a the static HDR metadata.
*/
memset(&meta, 0, sizeof meta);
meta.metadata_type = 0; /* Static Metadata Type 1 */
/* Duplicated field in UABI struct */
meta.hdmi_metadata_type1.metadata_type = meta.metadata_type;
switch (output->base.eotf_mode) {
case WESTON_EOTF_MODE_NONE:
assert(0 && "bad eotf_mode: none");
return -1;
case WESTON_EOTF_MODE_SDR:
/*
* Do not send any static HDR metadata. Video sinks should
* respond by switching to traditional SDR mode. If they
* do not, the kernel should fix that up.
*/
assert(output->hdr_output_metadata_blob_id == 0);
return 0;
case WESTON_EOTF_MODE_TRADITIONAL_HDR:
meta.hdmi_metadata_type1.eotf = 1; /* from CTA-861-G */
break;
case WESTON_EOTF_MODE_ST2084:
meta.hdmi_metadata_type1.eotf = 2; /* from CTA-861-G */
break;
case WESTON_EOTF_MODE_HLG:
meta.hdmi_metadata_type1.eotf = 3; /* from CTA-861-G */
break;
}
if (meta.hdmi_metadata_type1.eotf == 0) {
assert(0 && "bad eotf_mode");
return -1;
}
/* The other fields are intentionally left as zeroes. */
ret = drmModeCreatePropertyBlob(output->backend->drm.fd,
&meta, sizeof meta, &blob_id);
if (ret != 0) {
weston_log("Error: failed to create KMS blob for HDR metadata on output '%s': %s\n",
output->base.name, strerror(-ret));
return -1;
}
output->hdr_output_metadata_blob_id = blob_id;
return 0;
}
static int static int
drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
{ {
@ -474,6 +540,9 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
else else
state->protection = WESTON_HDCP_DISABLE; state->protection = WESTON_HDCP_DISABLE;
if (drm_output_ensure_hdr_output_metadata_blob(output) < 0)
goto err;
drm_output_render(state, damage); drm_output_render(state, damage);
scanout_state = drm_output_state_get_plane(state, scanout_state = drm_output_state_get_plane(state,
output->scanout_plane); output->scanout_plane);
@ -1845,6 +1914,12 @@ drm_output_deinit(struct weston_output *base)
drm_output_deinit_planes(output); drm_output_deinit_planes(output);
drm_output_detach_crtc(output); drm_output_detach_crtc(output);
if (output->hdr_output_metadata_blob_id) {
drmModeDestroyPropertyBlob(b->drm.fd,
output->hdr_output_metadata_blob_id);
output->hdr_output_metadata_blob_id = 0;
}
} }
static void static void
@ -1879,6 +1954,8 @@ drm_output_destroy(struct weston_output *base)
assert(!output->state_last); assert(!output->state_last);
drm_output_state_free(output->state_cur); drm_output_state_free(output->state_cur);
assert(output->hdr_output_metadata_blob_id == 0);
free(output); free(output);
} }

@ -973,10 +973,18 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
WDRM_CONNECTOR_CRTC_ID, 0); WDRM_CONNECTOR_CRTC_ID, 0);
} }
wl_list_for_each(head, &output->base.head_list, base.output_link) wl_list_for_each(head, &output->base.head_list, base.output_link) {
drm_connector_set_hdcp_property(&head->connector, drm_connector_set_hdcp_property(&head->connector,
state->protection, req); state->protection, req);
if (drm_connector_has_prop(&head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) {
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
output->hdr_output_metadata_blob_id);
}
}
if (ret != 0) { if (ret != 0) {
weston_log("couldn't set atomic CRTC/connector state\n"); weston_log("couldn't set atomic CRTC/connector state\n");
return ret; return ret;

@ -360,7 +360,7 @@ prune_eotf_modes_by_kms_support(struct drm_head *head, uint32_t *eotf_mask)
/* Without the KMS property, cannot do anything but SDR. */ /* Without the KMS property, cannot do anything but SDR. */
info = &head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA]; info = &head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA];
if (info->prop_id == 0) if (!head->backend->atomic_modeset || info->prop_id == 0)
*eotf_mask = WESTON_EOTF_MODE_SDR; *eotf_mask = WESTON_EOTF_MODE_SDR;
} }

Loading…
Cancel
Save