DRM: Add support for HDMI content type

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 <linkmauve@linkmauve.fr>
This commit is contained in:
Emmanuel Gil Peyrot 2021-10-02 17:10:37 +02:00 committed by Daniel Stone
parent 2e39630214
commit 1c5ce4c2cc
6 changed files with 100 additions and 0 deletions

View file

@ -2024,6 +2024,7 @@ drm_backend_output_configure(struct weston_output *output,
char *s; char *s;
char *modeline = NULL; char *modeline = NULL;
char *gbm_format = NULL; char *gbm_format = NULL;
char *content_type = NULL;
char *seat = NULL; char *seat = NULL;
api = weston_drm_output_get_api(output->compositor); 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); api->set_gbm_format(output, gbm_format);
free(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, ""); weston_config_section_get_string(section, "seat", &seat, "");
api->set_seat(output, seat); api->set_seat(output, seat);

View file

@ -93,6 +93,17 @@ struct weston_drm_output_api {
* This can be set only while the output is disabled. * This can be set only while the output is disabled.
*/ */
void (*set_max_bpc)(struct weston_output *output, unsigned max_bpc); 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 * static inline const struct weston_drm_output_api *

View file

@ -188,6 +188,7 @@ enum wdrm_connector_property {
WDRM_CONNECTOR_PANEL_ORIENTATION, WDRM_CONNECTOR_PANEL_ORIENTATION,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA, WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
WDRM_CONNECTOR_MAX_BPC, WDRM_CONNECTOR_MAX_BPC,
WDRM_CONNECTOR_CONTENT_TYPE,
WDRM_CONNECTOR__COUNT WDRM_CONNECTOR__COUNT
}; };
@ -220,6 +221,15 @@ enum wdrm_panel_orientation {
WDRM_PANEL_ORIENTATION__COUNT 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 * List of properties attached to DRM CRTCs
*/ */
@ -587,6 +597,8 @@ struct drm_output {
void (*virtual_destroy)(struct weston_output *base); void (*virtual_destroy)(struct weston_output *base);
submit_frame_cb virtual_submit_frame; submit_frame_cb virtual_submit_frame;
enum wdrm_content_type content_type;
}; };
void void

View file

@ -1425,6 +1425,38 @@ drm_output_set_max_bpc(struct weston_output *base, unsigned max_bpc)
output->max_bpc = 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 static int
drm_output_init_gamma_size(struct drm_output *output) 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_gbm_format,
drm_output_set_seat, drm_output_set_seat,
drm_output_set_max_bpc, drm_output_set_max_bpc,
drm_output_set_content_type,
}; };
static struct drm_backend * static struct drm_backend *

View file

@ -119,6 +119,14 @@ struct drm_property_enum_info panel_orientation_enums[] = {
[WDRM_PANEL_ORIENTATION_RIGHT_SIDE_UP] = { .name = "Right Side Up", }, [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[] = { const struct drm_property_info connector_props[] = {
[WDRM_CONNECTOR_EDID] = { .name = "EDID" }, [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
[WDRM_CONNECTOR_DPMS] = { [WDRM_CONNECTOR_DPMS] = {
@ -147,6 +155,11 @@ const struct drm_property_info connector_props[] = {
.name = "HDR_OUTPUT_METADATA", .name = "HDR_OUTPUT_METADATA",
}, },
[WDRM_CONNECTOR_MAX_BPC] = { .name = "max bpc", }, [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[] = { 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); 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 static int
drm_output_apply_state_atomic(struct drm_output_state *state, drm_output_apply_state_atomic(struct drm_output_state *state,
drmModeAtomicReq *req, 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) { 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);
ret |= drm_connector_set_content_type(&head->connector,
output->content_type, req);
if (drm_connector_has_prop(&head->connector, if (drm_connector_has_prop(&head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) { WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) {

View file

@ -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 (source and sink) support HDCP, and the backend has the implementation
of content-protection protocol. Currently, HDCP is supported by drm-backend. of content-protection protocol. Currently, HDCP is supported by drm-backend.
.TP 7 .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]* .BI "app-ids=" app-id[,app_id]*
A comma separated list of the IDs of applications to place on this output. 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 These IDs should match the application IDs as set with the xdg_shell.set_app_id