modesetting: Lay the foundation for enabling VRR

These changes have been ported from AMD GPU DDX driver.

This patch adds support for setting the CRTC variable refresh property
for suitable windows flipping via the Present extension.

In order for a window to be suitable for variable refresh it must have
the _VARIABLE_REFRESH property set by the MESA and inform Modesetting
DDX driver with window property updates.

Then the window must pass the checks required to be suitable for
Present extension flips - it must cover the entire X screen and no
other window may already be flipping. And also DRM connector should
be VRR capable.

With these conditions met every CRTC for the X screen will have their
variable refresh property set to true.

Kernel Changes to support this feature in I915 driver is under development.

Tested with DOTA2, Xonotic and custom GLX apps.

Signed-off-by: Uday Kiran Pichika <pichika.uday.kiran@intel.com>
This commit is contained in:
Uday Kiran Pichika 2020-06-18 11:31:31 +05:30 committed by Martin Peres
parent 4287879070
commit 9823ea4ed2
5 changed files with 170 additions and 2 deletions

View File

@ -706,6 +706,12 @@ msBlockHandler_oneshot(ScreenPtr pScreen, void *pTimeout)
drmmode_set_desired_modes(pScrn, &ms->drmmode, TRUE);
}
Bool
ms_window_has_variable_refresh(modesettingPtr ms, WindowPtr win) {
struct ms_vrr_priv *priv = dixLookupPrivate(&win->devPrivates, &ms->drmmode.vrrPrivateKeyRec);
return priv->variable_refresh;
}
static void
FreeRec(ScrnInfoPtr pScrn)
{
@ -1451,6 +1457,12 @@ CreateScreenResources(ScreenPtr pScreen)
pScrPriv->rrStartFlippingPixmapTracking = msStartFlippingPixmapTracking;
}
if (ms->vrr_support &&
!dixRegisterPrivateKey(&ms->drmmode.vrrPrivateKeyRec,
PRIVATE_WINDOW,
sizeof(struct ms_vrr_priv)))
return FALSE;
return ret;
}

View File

@ -43,6 +43,10 @@
#include "drmmode_display.h"
#define MS_LOGLEVEL_DEBUG 4
struct ms_vrr_priv {
Bool variable_refresh;
};
typedef enum {
OPTION_SW_CURSOR,
OPTION_DEVICE_PATH,
@ -122,6 +126,13 @@ typedef struct _modesettingRec {
Bool kms_has_modifiers;
/* VRR support */
Bool vrr_support;
WindowPtr flip_window;
Bool is_connector_vrr_capable;
uint32_t connector_prop_id;
/* shadow API */
struct {
Bool (*Setup)(ScreenPtr);
@ -224,3 +235,5 @@ Bool ms_do_pageflip(ScreenPtr screen,
#endif
int ms_flush_drm_events(ScreenPtr screen);
Bool ms_window_has_variable_refresh(modesettingPtr ms, WindowPtr win);
void ms_present_set_screen_vrr(ScrnInfoPtr scrn, Bool vrr_enabled);

View File

@ -2208,6 +2208,53 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
drmModeFreePlaneResources(kplane_res);
}
static uint32_t
drmmode_crtc_get_prop_id(uint32_t drm_fd,
drmModeObjectPropertiesPtr props,
char const* name)
{
uint32_t i, prop_id = 0;
for (i = 0; !prop_id && i < props->count_props; ++i) {
drmModePropertyPtr drm_prop =
drmModeGetProperty(drm_fd, props->props[i]);
if (!drm_prop)
continue;
if (strcmp(drm_prop->name, name) == 0)
prop_id = drm_prop->prop_id;
drmModeFreeProperty(drm_prop);
}
return prop_id;
}
static void
drmmode_crtc_vrr_init(int drm_fd, xf86CrtcPtr crtc)
{
drmModeObjectPropertiesPtr drm_props;
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
if (drmmode->vrr_prop_id)
return;
drm_props = drmModeObjectGetProperties(drm_fd,
drmmode_crtc->mode_crtc->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!drm_props)
return;
drmmode->vrr_prop_id = drmmode_crtc_get_prop_id(drm_fd,
drm_props,
"VRR_ENABLED");
drmModeFreeObjectProperties(drm_props);
}
static unsigned int
drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
{
@ -2250,6 +2297,8 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res
/* Hide any cursors which may be active from previous users */
drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
drmmode_crtc_vrr_init(drmmode->fd, crtc);
/* Mark num'th crtc as in use on this device. */
ms_ent->assigned_crtcs |= (1 << num);
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
@ -2918,6 +2967,40 @@ drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
}
static Bool
drmmode_connector_check_vrr_capable(uint32_t drm_fd, int connector_id)
{
uint32_t i;
Bool found = FALSE;
uint64_t prop_value = 0;
drmModeObjectPropertiesPtr props;
const char* prop_name = "VRR_CAPABLE";
props = drmModeObjectGetProperties(drm_fd, connector_id,
DRM_MODE_OBJECT_CONNECTOR);
for (i = 0; !found && i < props->count_props; ++i) {
drmModePropertyPtr drm_prop = drmModeGetProperty(drm_fd, props->props[i]);
if (!drm_prop)
continue;
if (strcasecmp(drm_prop->name, prop_name) == 0) {
prop_value = props->prop_values[i];
found = TRUE;
}
drmModeFreeProperty(drm_prop);
}
drmModeFreeObjectProperties(props);
if(found)
return prop_value ? TRUE : FALSE;
return FALSE;
}
static unsigned int
drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
{
@ -3049,6 +3132,9 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
}
}
ms->is_connector_vrr_capable =
drmmode_connector_check_vrr_capable(drmmode->fd,
drmmode_output->output_id);
return 1;
out_free_encoders:
@ -3968,6 +4054,23 @@ drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int *depth,
return;
}
void
drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled)
{
ScrnInfoPtr pScrn = crtc->scrn;
modesettingPtr ms = modesettingPTR(pScrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
if (drmmode->vrr_prop_id && drmmode_crtc->vrr_enabled != enabled &&
drmModeObjectSetProperty(ms->fd,
drmmode_crtc->mode_crtc->crtc_id,
DRM_MODE_OBJECT_CRTC,
drmmode->vrr_prop_id,
enabled) == 0)
drmmode_crtc->vrr_enabled = enabled;
}
/*
* We hook the screen's cursor-sprite (swcursor) functions to see if a swcursor
* is active. When a swcursor is active we disable page-flipping.

View File

@ -112,6 +112,7 @@ typedef struct {
DevPrivateKeyRec pixmapPrivateKeyRec;
DevScreenPrivateKeyRec spritePrivateKeyRec;
DevPrivateKeyRec vrrPrivateKeyRec;
/* Number of SW cursors currently visible on this screen */
int sprites_visible;
@ -127,6 +128,8 @@ typedef struct {
Bool dri2_enable;
Bool present_enable;
uint32_t vrr_prop_id;
} drmmode_rec, *drmmode_ptr;
typedef struct {
@ -193,6 +196,8 @@ typedef struct {
Bool enable_flipping;
Bool flipping_active;
Bool vrr_enabled;
} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
typedef struct {
@ -293,5 +298,6 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
int drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data);
void drmmode_set_dpms(ScrnInfoPtr scrn, int PowerManagementMode, int flags);
void drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled);
#endif

View File

@ -70,6 +70,22 @@ ms_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc)
return ms_get_crtc_ust_msc(xf86_crtc, ust, msc);
}
/*
* Changes the variable refresh state for every CRTC on the screen.
*/
void
ms_present_set_screen_vrr(ScrnInfoPtr scrn, Bool vrr_enabled)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CrtcPtr crtc;
int i;
for (i = 0; i < config->num_crtc; i++) {
crtc = config->crtc[i];
drmmode_crtc_set_vrr(crtc, vrr_enabled);
}
}
/*
* Called when the queued vblank event has occurred
*/
@ -299,7 +315,12 @@ ms_present_check_flip(RRCrtcPtr crtc,
if (ms->drmmode.sprites_visible > 0)
return FALSE;
return ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason);
if(!ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason))
return FALSE;
ms->flip_window = window;
return TRUE;
}
/*
@ -321,7 +342,7 @@ ms_present_flip(RRCrtcPtr crtc,
Bool ret;
struct ms_present_vblank_event *event;
if (!ms_present_check_flip(crtc, screen->root, pixmap, sync_flip, NULL))
if (!ms_present_check_flip(crtc, ms->flip_window, pixmap, sync_flip, NULL))
return FALSE;
event = calloc(1, sizeof(struct ms_present_vblank_event));
@ -334,6 +355,17 @@ ms_present_flip(RRCrtcPtr crtc,
event->event_id = event_id;
event->unflip = FALSE;
/* A window can only flip if it covers the entire X screen.
* Only one window can flip at a time.
*
* If the window also has the variable refresh property then
* variable refresh supported can be enabled on every CRTC.
*/
if (ms->vrr_support && ms->is_connector_vrr_capable &&
ms_window_has_variable_refresh(ms, ms->flip_window)) {
ms_present_set_screen_vrr(scrn, TRUE);
}
ret = ms_do_pageflip(screen, pixmap, event, drmmode_crtc->vblank_pipe, !sync_flip,
ms_present_flip_handler, ms_present_flip_abort,
"Present-flip");
@ -356,6 +388,8 @@ ms_present_unflip(ScreenPtr screen, uint64_t event_id)
int i;
struct ms_present_vblank_event *event;
ms_present_set_screen_vrr(scrn, FALSE);
event = calloc(1, sizeof(struct ms_present_vblank_event));
if (!event)
return;