From 1c5ce4c2cc8cb15c2ed8e76b73c107cb1389a333 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 2 Oct 2021 17:10:37 +0200 Subject: [PATCH] DRM: Add support for HDMI content type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some monitors expose a selector for the kind of content that will get displayed, allowing them to optimise their settings for this particular content type. I got access to such a monitor, sadly even setting it to game mode didn’t lower its atrocious latency, but drm_info[1] reports it to be set correctly so hopefully it’ll work better with other monitors. [1] https://github.com/ascent12/drm_info Signed-off-by: Emmanuel Gil Peyrot --- compositor/main.c | 7 ++++++ include/libweston/backend-drm.h | 11 ++++++++++ libweston/backend-drm/drm-internal.h | 12 ++++++++++ libweston/backend-drm/drm.c | 33 ++++++++++++++++++++++++++++ libweston/backend-drm/kms.c | 33 ++++++++++++++++++++++++++++ man/weston.ini.man | 4 ++++ 6 files changed, 100 insertions(+) diff --git a/compositor/main.c b/compositor/main.c index 5689458b5..e93d551bf 100644 --- a/compositor/main.c +++ b/compositor/main.c @@ -2024,6 +2024,7 @@ drm_backend_output_configure(struct weston_output *output, char *s; char *modeline = NULL; char *gbm_format = NULL; + char *content_type = NULL; char *seat = NULL; api = weston_drm_output_get_api(output->compositor); @@ -2080,6 +2081,12 @@ drm_backend_output_configure(struct weston_output *output, api->set_gbm_format(output, gbm_format); free(gbm_format); + weston_config_section_get_string(section, + "content-type", &content_type, NULL); + if (api->set_content_type(output, content_type) < 0) + return -1; + free(content_type); + weston_config_section_get_string(section, "seat", &seat, ""); api->set_seat(output, seat); diff --git a/include/libweston/backend-drm.h b/include/libweston/backend-drm.h index 071125fa5..cc657c693 100644 --- a/include/libweston/backend-drm.h +++ b/include/libweston/backend-drm.h @@ -93,6 +93,17 @@ struct weston_drm_output_api { * This can be set only while the output is disabled. */ void (*set_max_bpc)(struct weston_output *output, unsigned max_bpc); + + /** The content type primarily used on the output. Valid values are: + * - NULL or "no data" - No information is provided about the usage of the + * output + * - "graphics" + * - "photo" + * - "cinema" + * - "game" + */ + int (*set_content_type)(struct weston_output *output, + const char *content_type); }; static inline const struct weston_drm_output_api * diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 1ee1974c2..12548be41 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -188,6 +188,7 @@ enum wdrm_connector_property { WDRM_CONNECTOR_PANEL_ORIENTATION, WDRM_CONNECTOR_HDR_OUTPUT_METADATA, WDRM_CONNECTOR_MAX_BPC, + WDRM_CONNECTOR_CONTENT_TYPE, WDRM_CONNECTOR__COUNT }; @@ -220,6 +221,15 @@ enum wdrm_panel_orientation { WDRM_PANEL_ORIENTATION__COUNT }; +enum wdrm_content_type { + WDRM_CONTENT_TYPE_NO_DATA = 0, + WDRM_CONTENT_TYPE_GRAPHICS, + WDRM_CONTENT_TYPE_PHOTO, + WDRM_CONTENT_TYPE_CINEMA, + WDRM_CONTENT_TYPE_GAME, + WDRM_CONTENT_TYPE__COUNT +}; + /** * List of properties attached to DRM CRTCs */ @@ -587,6 +597,8 @@ struct drm_output { void (*virtual_destroy)(struct weston_output *base); submit_frame_cb virtual_submit_frame; + + enum wdrm_content_type content_type; }; void diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 96b0373a8..d7dc01f72 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -1425,6 +1425,38 @@ drm_output_set_max_bpc(struct weston_output *base, unsigned max_bpc) output->max_bpc = max_bpc; } +static const struct { const char *name; uint32_t token; } content_types[] = { + { "no data", WDRM_CONTENT_TYPE_NO_DATA }, + { "graphics", WDRM_CONTENT_TYPE_GRAPHICS }, + { "photo", WDRM_CONTENT_TYPE_PHOTO }, + { "cinema", WDRM_CONTENT_TYPE_CINEMA }, + { "game", WDRM_CONTENT_TYPE_GAME }, +}; + +static int +drm_output_set_content_type(struct weston_output *base, + const char *content_type) +{ + unsigned int i; + struct drm_output *output = to_drm_output(base); + + if (content_type == NULL) { + output->content_type = WDRM_CONTENT_TYPE_NO_DATA; + return 0; + } + + for (i = 0; i < ARRAY_LENGTH(content_types); i++) + if (strcmp(content_types[i].name, content_type) == 0) { + output->content_type = content_types[i].token; + return 0; + } + + weston_log("Error: unknown content-type for output %s: \"%s\"\n", + base->name, content_type); + output->content_type = WDRM_CONTENT_TYPE_NO_DATA; + return -1; +} + static int drm_output_init_gamma_size(struct drm_output *output) { @@ -3084,6 +3116,7 @@ static const struct weston_drm_output_api api = { drm_output_set_gbm_format, drm_output_set_seat, drm_output_set_max_bpc, + drm_output_set_content_type, }; static struct drm_backend * diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index 6c6e7e592..11ca16c06 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -119,6 +119,14 @@ struct drm_property_enum_info panel_orientation_enums[] = { [WDRM_PANEL_ORIENTATION_RIGHT_SIDE_UP] = { .name = "Right Side Up", }, }; +struct drm_property_enum_info content_type_enums[] = { + [WDRM_CONTENT_TYPE_NO_DATA] = { .name = "No Data", }, + [WDRM_CONTENT_TYPE_GRAPHICS] = { .name = "Graphics", }, + [WDRM_CONTENT_TYPE_PHOTO] = { .name = "Photo", }, + [WDRM_CONTENT_TYPE_CINEMA] = { .name = "Cinema", }, + [WDRM_CONTENT_TYPE_GAME] = { .name = "Game", }, +}; + const struct drm_property_info connector_props[] = { [WDRM_CONNECTOR_EDID] = { .name = "EDID" }, [WDRM_CONNECTOR_DPMS] = { @@ -147,6 +155,11 @@ const struct drm_property_info connector_props[] = { .name = "HDR_OUTPUT_METADATA", }, [WDRM_CONNECTOR_MAX_BPC] = { .name = "max bpc", }, + [WDRM_CONNECTOR_CONTENT_TYPE] = { + .name = "content type", + .enum_values = content_type_enums, + .num_enum_values = WDRM_CONTENT_TYPE__COUNT, + }, }; const struct drm_property_info crtc_props[] = { @@ -939,6 +952,24 @@ drm_connector_set_max_bpc(struct drm_connector *connector, WDRM_CONNECTOR_MAX_BPC, max_bpc); } +static int +drm_connector_set_content_type(struct drm_connector *connector, + enum wdrm_content_type content_type, + drmModeAtomicReq *req) +{ + struct drm_property_enum_info *enum_info; + uint64_t prop_val; + struct drm_property_info *props = connector->props; + + if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_CONTENT_TYPE)) + return 0; + + enum_info = props[WDRM_CONNECTOR_CONTENT_TYPE].enum_values; + prop_val = enum_info[content_type].value; + return connector_add_prop(req, connector, + WDRM_CONNECTOR_CONTENT_TYPE, prop_val); +} + static int drm_output_apply_state_atomic(struct drm_output_state *state, drmModeAtomicReq *req, @@ -992,6 +1023,8 @@ drm_output_apply_state_atomic(struct drm_output_state *state, wl_list_for_each(head, &output->base.head_list, base.output_link) { drm_connector_set_hdcp_property(&head->connector, state->protection, req); + ret |= drm_connector_set_content_type(&head->connector, + output->content_type, req); if (drm_connector_has_prop(&head->connector, WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) { diff --git a/man/weston.ini.man b/man/weston.ini.man index 24f2138bb..b4084ddd1 100644 --- a/man/weston.ini.man +++ b/man/weston.ini.man @@ -543,6 +543,10 @@ content-protection can actually be realized, only if the hardware (source and sink) support HDCP, and the backend has the implementation of content-protection protocol. Currently, HDCP is supported by drm-backend. .TP 7 +.BI "content-type=" content_type +The type of the content being primarily displayed to this output. Can be "no +data" (default), "graphics", "photo", "cinema" or "game". +.TP 7 .BI "app-ids=" app-id[,app_id]* A comma separated list of the IDs of applications to place on this output. These IDs should match the application IDs as set with the xdg_shell.set_app_id