From bc59d3fc76047bcdd20e9750591e06227b9cf39e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 7 Jan 2015 19:44:12 +0000 Subject: [PATCH] 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 Signed-off-by: Chris Wilson --- src/sna/sna.h | 1 + src/sna/sna_display.c | 23 ++++++++++++++- src/sna/sna_driver.c | 68 +++++++++++++++++++++++++++++++++---------- src/sna/sna_present.c | 10 +++++++ 4 files changed, 86 insertions(+), 16 deletions(-) diff --git a/src/sna/sna.h b/src/sna/sna.h index 18425e30..7a1bf34f 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -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; diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 5f6bc424..cf871bcb 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -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; diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index 8a3599c7..dcd74ecb 100644 --- a/src/sna/sna_driver.c +++ b/src/sna/sna_driver.c @@ -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(); diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c index 6dd6fe88..81cf669f 100644 --- a/src/sna/sna_present.c +++ b/src/sna/sna_present.c @@ -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;