diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 37bc51657..513816c70 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -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; } diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 7ee9f6827..7391bc4ab 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -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); diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 9dd4b298f..5dbfa4149 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -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. diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index 2fb049bca..6360dd048 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -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 diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index fea2d663e..6e5b58938 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -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;