diff options
author | disher@chromium.org <disher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-08 15:27:21 +0000 |
---|---|---|
committer | disher@chromium.org <disher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-08 15:27:21 +0000 |
commit | 594842ef04f40e20daa300e992be8a1507852b48 (patch) | |
tree | aca305e87d5c4340dc39c7a8df1a741d1f96a1e2 /chromeos | |
parent | 242ab286be750c2dfcaa725bb811792ee252112d (diff) | |
download | chromium_src-594842ef04f40e20daa300e992be8a1507852b48.zip chromium_src-594842ef04f40e20daa300e992be8a1507852b48.tar.gz chromium_src-594842ef04f40e20daa300e992be8a1507852b48.tar.bz2 |
Detect output state at startup to avoid changes
Resetting the state of the outputs causes a black flash on the screen so avoid
doing this in the cases where the outputs were already configured such that they
were in a state we can recognize.
BUG=chromium:130943
TEST=Manually tested on lumpy with extra instrumentation to ensure that logging
in as guest does not change the CRTCs.
Review URL: https://chromiumcodereview.appspot.com/10532053
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141209 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos')
-rw-r--r-- | chromeos/monitor/output_configurator.cc | 109 | ||||
-rw-r--r-- | chromeos/monitor/output_configurator.h | 7 |
2 files changed, 114 insertions, 2 deletions
diff --git a/chromeos/monitor/output_configurator.cc b/chromeos/monitor/output_configurator.cc index cda21a7..c601b9c 100644 --- a/chromeos/monitor/output_configurator.cc +++ b/chromeos/monitor/output_configurator.cc @@ -158,6 +158,26 @@ static void CreateFrameBuffer(Display* display, int mm_height = height * kPixelsToMmScale; XRRSetScreenSize(display, window, width, height, mm_width, mm_height); } + +// A helper to get the current CRTC, Mode, and height for a given output. This +// is read from the XRandR configuration and not any of our caches. +static void GetOutputConfiguration(Display* display, + XRRScreenResources* screen, + RROutput output, + RRCrtc* crtc, + RRMode* mode, + int* height) { + XRROutputInfo* output_info = XRRGetOutputInfo(display, screen, output); + CHECK(output_info != NULL); + *crtc = output_info->crtc; + XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display, screen, *crtc); + if (crtc_info != NULL) { + *mode = crtc_info->mode; + *height = crtc_info->height; + XRRFreeCrtcInfo(crtc_info); + } + XRRFreeOutputInfo(output_info); +} } // namespace bool OutputConfigurator::TryRecacheOutputs(Display* display, @@ -320,8 +340,15 @@ OutputConfigurator::OutputConfigurator() CHECK(screen != NULL); bool did_detect_outputs = TryRecacheOutputs(display, screen); CHECK(did_detect_outputs); - State state = GetDefaultState(); - UpdateCacheAndXrandrToState(display, screen, window, state); + State current_state = InferCurrentState(display, screen); + if (current_state == STATE_INVALID) { + // Unknown state. Transition into the default state. + State state = GetDefaultState(); + UpdateCacheAndXrandrToState(display, screen, window, state); + } else { + // This is a valid state so just save it to |output_state_|. + output_state_ = current_state; + } // Find xrandr_event_base_ since we need it to interpret events, later. int error_base_ignored = 0; XRRQueryExtension(display, &xrandr_event_base_, &error_base_ignored); @@ -473,6 +500,84 @@ State OutputConfigurator::GetDefaultState() const { return state; } +State OutputConfigurator::InferCurrentState(Display* display, + XRRScreenResources* screen) const { + // STATE_INVALID will be our default or "unknown" state. + State state = STATE_INVALID; + // First step: count the number of connected outputs. + if (secondary_output_index_ == -1) { + // No secondary display. + if (primary_output_index_ == -1) { + // No primary display implies HEADLESS. + state = STATE_HEADLESS; + } else { + // The common case of primary-only. + // The only sanity check we require in this case is that the current mode + // of the output's CRTC is the ideal mode we determined for it. + RRCrtc primary_crtc = None; + RRMode primary_mode = None; + int primary_height = 0; + GetOutputConfiguration(display, + screen, + output_cache_[primary_output_index_].output, + &primary_crtc, + &primary_mode, + &primary_height); + if (primary_mode == output_cache_[primary_output_index_].ideal_mode) + state = STATE_SINGLE; + } + } else { + // We have two displays attached so we need to look at their configuration. + // Note that, for simplicity, we will only detect the states that we would + // have used and will assume anything unexpected is INVALID (which should + // not happen in any expected usage scenario). + RRCrtc primary_crtc = None; + RRMode primary_mode = None; + int primary_height = 0; + GetOutputConfiguration(display, + screen, + output_cache_[primary_output_index_].output, + &primary_crtc, + &primary_mode, + &primary_height); + RRCrtc secondary_crtc = None; + RRMode secondary_mode = None; + int secondary_height = 0; + GetOutputConfiguration(display, + screen, + output_cache_[secondary_output_index_].output, + &secondary_crtc, + &secondary_mode, + &secondary_height); + // Make sure the CRTCs are matched to the expected outputs. + if ((output_cache_[primary_output_index_].crtc == primary_crtc) && + (output_cache_[secondary_output_index_].crtc == secondary_crtc)) { + // Check the mode matching: either both mirror or both ideal. + if ((output_cache_[primary_output_index_].mirror_mode == primary_mode) && + (output_cache_[secondary_output_index_].mirror_mode == + secondary_mode)) { + // We are already in mirror mode. + state = STATE_DUAL_MIRROR; + } else if ((output_cache_[primary_output_index_].ideal_mode == + primary_mode) && + (output_cache_[secondary_output_index_].ideal_mode == + secondary_mode)) { + // Both outputs are in their "ideal" mode so check their Y-offsets to + // see which "ideal" configuration this is. + if (primary_height == output_cache_[secondary_output_index_].y) { + // Secondary is tiled first. + state = STATE_DUAL_SECONDARY_ONLY; + } else if (secondary_height == output_cache_[primary_output_index_].y) { + // Primary is tiled first. + state = STATE_DUAL_PRIMARY_ONLY; + } + } + } + } + + return state; +} + bool OutputConfigurator::CycleDisplayMode() { VLOG(1) << "CycleDisplayMode"; bool did_change = false; diff --git a/chromeos/monitor/output_configurator.h b/chromeos/monitor/output_configurator.h index b59474f2..4e6bb5f 100644 --- a/chromeos/monitor/output_configurator.h +++ b/chromeos/monitor/output_configurator.h @@ -103,6 +103,13 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher { // displays. State GetDefaultState() const; + // Called during start-up to determine what the current state of the displays + // appears to be, by investigating how the outputs compare to the data stored + // in |output_cache_|. Returns STATE_INVALID if the current display state + // doesn't match any supported state. |output_cache_| must be up-to-date with + // regards to the state of X or this method may return incorrect results. + State InferCurrentState(Display* display, XRRScreenResources* screen) const; + // This is detected by the constructor to determine whether or not we should // be enabled. If we aren't running on ChromeOS, we can't assume that the // Xrandr X11 extension is supported. |