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;