sna: Differentiate between disabling CRTC and turning off DPMS

xf86DisableUnusedFunctions() uses crtc->dpms(off) to disable unused
pipes. In this case, we do want to explicitly disable the CRTC to
release any shared state (e.g. PLLs and encoders). However, the user can
also request for the DPMS to be disabled, either via the DPMS extension
or the ScreenSaver. Here, we don't want to full disable the pipe as that
incurs extra latency (and risk of failure) when switching the display
back on. In order to distinguish the two cases, we can hook into the
user paths and skip disabling the CRTCs.

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2015-01-07 19:44:12 +00:00
parent 574ab948af
commit bc59d3fc76
4 changed files with 86 additions and 16 deletions

View File

@ -286,6 +286,7 @@ struct sna {
unsigned shadow_active;
unsigned flip_active;
bool dirty;
bool hidden;
int max_crtc_width, max_crtc_height;
RegionRec shadow_region;

View File

@ -537,6 +537,7 @@ sna_backlight_uevent(int fd, void *closure)
TRUE, FALSE);
}
}
DBG(("%s: complete\n", __FUNCTION__));
}
static void sna_backlight_pre_init(struct sna *sna)
@ -584,6 +585,7 @@ static void sna_backlight_drain_uevents(struct sna *sna)
if (sna->mode.backlight_monitor == NULL)
return;
DBG(("%s()\n", __FUNCTION__));
sna_backlight_uevent(udev_monitor_get_fd(sna->mode.backlight_monitor),
sna);
}
@ -4108,6 +4110,8 @@ static bool disable_unused_crtc(struct sna *sna)
bool update = false;
int o, c;
DBG(("%s\n", __FUNCTION__));
for (c = 0; c < sna->mode.num_real_crtc; c++) {
xf86CrtcPtr crtc = config->crtc[c];
@ -6029,6 +6033,11 @@ sna_mode_enable(struct sna *sna)
if (!sna->scrn->vtSema)
return;
if (sna->mode.hidden) {
DBG(("%s: hidden outputs\n", __FUNCTION__));
return;
}
for (i = 0; i < sna->mode.num_real_crtc; i++) {
xf86CrtcPtr crtc = config->crtc[i];
@ -6112,8 +6121,15 @@ sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
return NULL;
/* If we do not own the VT, we do not own the CRTC either */
if (!sna->scrn->vtSema)
if (!sna->scrn->vtSema) {
DBG(("%s: none, VT switched\n", __FUNCTION__));
return NULL;
}
if (sna->mode.hidden) {
DBG(("%s: none, hidden outputs\n", __FUNCTION__));
return NULL;
}
DBG(("%s for box=(%d, %d), (%d, %d)\n",
__FUNCTION__, box->x1, box->y1, box->x2, box->y2));
@ -7016,6 +7032,11 @@ void sna_mode_redisplay(struct sna *sna)
RegionPtr region;
int i;
if (sna->mode.hidden) {
DBG(("%s: hidden outputs, skipping\n", __FUNCTION__));
return;
}
if (!sna->mode.shadow_damage)
return;

View File

@ -279,29 +279,67 @@ static Bool sna_create_screen_resources(ScreenPtr screen)
return TRUE;
}
static void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int i;
DBG(("%s(mode=%d, flags=%d), vtSema=%d\n",
__FUNCTION__, mode, flags, scrn->vtSema));
if (!scrn->vtSema)
return;
/* Opencoded version of xf86DPMSSet().
*
* The principle difference is to skip calling crtc->dpms() when
* turning off the display. This (on recent enough kernels at
* least) should be equivalent in power consumption, but require
* less work (hence quicker and less likely to fail) when switching
* back on.
*/
if (mode == DPMSModeOff) {
for (i = 0; i < config->num_output; i++) {
xf86OutputPtr output = config->output[i];
if (output->crtc != NULL)
output->funcs->dpms(output, mode);
}
} else {
/* Re-enable CRTC that have been forced off via other means */
for (i = 0; i < config->num_crtc; i++) {
xf86CrtcPtr crtc = config->crtc[i];
if (crtc->enabled)
crtc->funcs->dpms(crtc, mode);
}
for (i = 0; i < config->num_output; i++) {
xf86OutputPtr output = config->output[i];
if (output->crtc != NULL)
output->funcs->dpms(output, mode);
}
}
sna_crtc_config_notify(xf86ScrnToScreen(scrn));
to_sna(scrn)->mode.hidden = mode == DPMSModeOff;
DBG(("%s: hiding outputs? %d\n", __FUNCTION__, to_sna(scrn)->mode.hidden));
}
static Bool sna_save_screen(ScreenPtr screen, int mode)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
DBG(("%s(mode=%d)\n", __FUNCTION__, mode));
if (!scrn->vtSema)
return FALSE;
DBG(("%s(mode=%d [unblank=%d])\n",
__FUNCTION__, mode, xf86IsUnblank(mode)));
xf86SaveScreen(screen, mode);
sna_crtc_config_notify(screen);
/* We have to unroll xf86SaveScreen() here as it is called
* by DPMSSet() nullifying our special handling crtc->dpms()
* in sna_dpms_set().
*/
sna_dpms_set(scrn,
xf86IsUnblank(mode) ? DPMSModeOn : DPMSModeOff,
0);
return TRUE;
}
static void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
{
DBG(("%s(mode=%d, flags=%d)\n", __FUNCTION__, mode));
if (!scrn->vtSema)
return;
xf86DPMSSet(scrn, mode, flags);
sna_crtc_config_notify(xf86ScrnToScreen(scrn));
}
static void sna_selftest(void)
{
sna_damage_selftest();

View File

@ -224,6 +224,16 @@ sna_present_check_flip(RRCrtcPtr crtc,
pixmap->drawable.serialNumber,
sync_flip));
if (!sna->scrn->vtSema) {
DBG(("%s: VT switched away, no flips\n", __FUNCTION__));
return FALSE;
}
if (sna->mode.hidden) {
DBG(("%s: DPMS off, no flips\n", __FUNCTION__));
return FALSE;
}
if (sna->flags & SNA_NO_FLIP) {
DBG(("%s: flips not suported\n", __FUNCTION__));
return FALSE;