drm-backend: Add Variable Refresh Rate modes

Query the vrr_capable property for heads, and expose it to frontends.

Currently we only support game mode VRR, but expose VRR capabilities as
an enum in anticipation of supporting QMS VRR in the future.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
This commit is contained in:
Derek Foreman 2025-02-03 12:23:17 -06:00 committed by Marius Vlad
parent de6f0b870a
commit c321cc3020
7 changed files with 67 additions and 0 deletions

View file

@ -522,6 +522,8 @@ struct weston_head {
* When a client uses this request, we add the wl_resource we create to
* this list. */
struct wl_list cm_output_resource_list;
uint32_t supported_vrr_mode_mask;
};
enum weston_output_power_state {
@ -531,6 +533,15 @@ enum weston_output_power_state {
WESTON_OUTPUT_POWER_NORMAL
};
enum weston_vrr_mode {
/** No VRR */
WESTON_VRR_MODE_NONE = 0,
/** Game mode VRR */
WESTON_VRR_MODE_GAME = 1 << 0,
};
#define WESTON_VRR_MODE_ALL_MASK \
((uint32_t)(WESTON_VRR_MODE_GAME))
struct weston_plane {
struct weston_compositor *compositor;
int32_t x, y;

View file

@ -123,6 +123,7 @@ enum wdrm_connector_property {
WDRM_CONNECTOR_MAX_BPC,
WDRM_CONNECTOR_CONTENT_TYPE,
WDRM_CONNECTOR_COLORSPACE,
WDRM_CONNECTOR_VRR_CAPABLE,
WDRM_CONNECTOR__COUNT
};

View file

@ -2653,6 +2653,16 @@ drm_connector_init(struct drm_device *device, struct drm_connector *connector,
connector->props_drm = NULL;
}
static const char *
vrr_mode_to_str(enum weston_vrr_mode vrr_mode)
{
switch (vrr_mode) {
case WESTON_VRR_MODE_NONE: return "(none)";
case WESTON_VRR_MODE_GAME: return "Game";
}
return "???";
}
static void
drm_connector_fini(struct drm_connector *connector)
{
@ -2661,6 +2671,12 @@ drm_connector_fini(struct drm_connector *connector)
drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
}
static char *
weston_vrr_mask_to_str(uint32_t mask)
{
return bits_to_str(mask, vrr_mode_to_str);
}
static void
drm_head_log_info(struct drm_head *head, const char *msg)
{
@ -2687,6 +2703,14 @@ drm_head_log_info(struct drm_head *head, const char *msg)
str);
}
free(str);
str = weston_vrr_mask_to_str(head->base.supported_vrr_mode_mask);
if (str) {
weston_log_continue(STAMP_SPACE
"Supported VRR modes: (none), %s\n",
str);
}
free(str);
} else {
weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
head->base.name, msg, head->connector.connector_id);

View file

@ -249,6 +249,9 @@ const struct drm_property_info connector_props[] = {
.enum_values = colorspace_enums,
.num_enum_values = WDRM_COLORSPACE__COUNT,
},
[WDRM_CONNECTOR_VRR_CAPABLE] = {
.name = "vrr_capable",
},
};
const struct drm_property_info crtc_props[] = {

View file

@ -599,6 +599,8 @@ update_head_from_connector(struct drm_head *head)
struct drm_connector *connector = &head->connector;
drmModeObjectProperties *props = connector->props_drm;
drmModeConnector *conn = connector->conn;
int vrr_capable;
uint32_t vrr_mode_mask = 0;
weston_head_set_non_desktop(&head->base,
check_non_desktop(connector, props));
@ -630,11 +632,18 @@ update_head_from_connector(struct drm_head *head)
dhi.serial_number);
prune_eotf_modes_by_kms_support(head, &dhi.eotf_mask);
weston_head_set_supported_eotf_mask(&head->base, dhi.eotf_mask);
dhi.colorimetry_mask &= drm_head_get_kms_colorimetry_modes(head);
weston_head_set_supported_colorimetry_mask(&head->base, dhi.colorimetry_mask);
vrr_capable = drm_property_get_value(&head->connector.props[WDRM_CONNECTOR_VRR_CAPABLE],
head->connector.props_drm, 0);
if (vrr_capable)
vrr_mode_mask = WESTON_VRR_MODE_GAME;
weston_head_set_supported_vrr_modes_mask(&head->base, vrr_mode_mask);
drm_head_info_fini(&dhi);
}

View file

@ -177,6 +177,9 @@ void
weston_head_set_supported_colorimetry_mask(struct weston_head *head,
uint32_t colorimetry_mask);
void
weston_head_set_supported_vrr_modes_mask(struct weston_head *head,
uint32_t vrr_modes_mask);
/* weston_output */
void

View file

@ -7112,6 +7112,22 @@ weston_head_set_supported_colorimetry_mask(struct weston_head *head,
weston_head_set_device_changed(head);
}
WL_EXPORT void
weston_head_set_supported_vrr_modes_mask(struct weston_head *head,
uint32_t vrr_mode_mask)
{
weston_assert_legal_bits(head->compositor,
vrr_mode_mask,
WESTON_VRR_MODE_ALL_MASK);
if (head->supported_vrr_mode_mask == vrr_mode_mask)
return;
head->supported_vrr_mode_mask = vrr_mode_mask;
weston_head_set_device_changed(head);
}
WL_EXPORT void
weston_head_set_content_protection_status(struct weston_head *head,
enum weston_hdcp_protection status)