Skip to content

Commit

Permalink
chromeos: Save display power state on config failure.
Browse files Browse the repository at this point in the history
Make DisplayConfigurator save the requested display power
state even when it fails to configure CRTCs. This lets the
previously-requested state be used for future mode changes.

BUG=chrome-os-partner:31571

Review URL: https://codereview.chromium.org/597683004

Cr-Commit-Position: refs/heads/master@{#296798}
  • Loading branch information
derat authored and Commit bot committed Sep 25, 2014
1 parent e0b1677 commit 4a06278
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 28 deletions.
3 changes: 2 additions & 1 deletion chrome/browser/chromeos/display/display_preferences.cc
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ void StoreDisplayPowerState(DisplayPowerState power_state) {

void StoreCurrentDisplayPowerState() {
StoreDisplayPowerState(
ash::Shell::GetInstance()->display_configurator()->power_state());
ash::Shell::GetInstance()->display_configurator()->
requested_power_state());
}

void StoreCurrentDisplayRotationLockPrefs() {
Expand Down
11 changes: 6 additions & 5 deletions chrome/browser/chromeos/display/display_preferences_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ TEST_F(DisplayPreferencesTest, PairedLayoutOverrides) {
LoadDisplayPreferences(true);
// DisplayPowerState should be ignored at boot.
EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON,
shell->display_configurator()->power_state());
shell->display_configurator()->requested_power_state());

shell->display_manager()->UpdateDisplays();
// Check if the layout settings are notified to the system properly.
Expand Down Expand Up @@ -623,7 +623,8 @@ TEST_F(DisplayPreferencesTest, DisplayPowerStateAfterRestart) {
chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON);
LoadDisplayPreferences(false);
EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
ash::Shell::GetInstance()->display_configurator()->power_state());
ash::Shell::GetInstance()->display_configurator()->
requested_power_state());
}

TEST_F(DisplayPreferencesTest, DontSaveAndRestoreAllOff) {
Expand All @@ -633,20 +634,20 @@ TEST_F(DisplayPreferencesTest, DontSaveAndRestoreAllOff) {
LoadDisplayPreferences(false);
// DisplayPowerState should be ignored at boot.
EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
shell->display_configurator()->power_state());
shell->display_configurator()->requested_power_state());

StoreDisplayPowerStateForTest(
chromeos::DISPLAY_POWER_ALL_OFF);
EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
shell->display_configurator()->power_state());
shell->display_configurator()->requested_power_state());
EXPECT_EQ("internal_off_external_on",
local_state()->GetString(prefs::kDisplayPowerState));

// Don't try to load
local_state()->SetString(prefs::kDisplayPowerState, "all_off");
LoadDisplayPreferences(false);
EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
shell->display_configurator()->power_state());
shell->display_configurator()->requested_power_state());
}

// Tests that display configuration changes caused by MaximizeModeController
Expand Down
39 changes: 23 additions & 16 deletions ui/display/chromeos/display_configurator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ DisplayConfigurator::DisplayConfigurator()
is_panel_fitting_enabled_(false),
configure_display_(base::SysInfo::IsRunningOnChromeOS()),
display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
power_state_(chromeos::DISPLAY_POWER_ALL_ON),
requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
current_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
next_display_protection_client_id_(1) {}

DisplayConfigurator::~DisplayConfigurator() {
Expand All @@ -179,7 +180,7 @@ void DisplayConfigurator::SetDelegateForTesting(
void DisplayConfigurator::SetInitialDisplayPower(
chromeos::DisplayPowerState power_state) {
DCHECK_EQ(display_state_, MULTIPLE_DISPLAY_STATE_INVALID);
power_state_ = power_state;
requested_power_state_ = current_power_state_ = power_state;
}

void DisplayConfigurator::Init(bool is_panel_fitting_enabled) {
Expand All @@ -206,9 +207,10 @@ void DisplayConfigurator::ForceInitialConfigure(
UpdateCachedDisplays();
if (cached_displays_.size() > 1 && background_color_argb)
native_display_delegate_->SetBackgroundColor(background_color_argb);
const MultipleDisplayState new_state = ChooseDisplayState(power_state_);
const bool success =
EnterStateOrFallBackToSoftwareMirroring(new_state, power_state_);
const MultipleDisplayState new_state = ChooseDisplayState(
requested_power_state_);
const bool success = EnterStateOrFallBackToSoftwareMirroring(
new_state, requested_power_state_);

// Force the DPMS on chrome startup as the driver doesn't always detect
// that all displays are on when signing out.
Expand Down Expand Up @@ -452,7 +454,8 @@ bool DisplayConfigurator::SetDisplayPower(
<< DisplayPowerStateToString(power_state) << " flags=" << flags
<< ", configure timer="
<< (configure_timer_.IsRunning() ? "Running" : "Stopped");
if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe))
if (power_state == current_power_state_ &&
!(flags & kSetDisplayPowerForceProbe))
return true;

native_display_delegate_->GrabServer();
Expand Down Expand Up @@ -480,7 +483,7 @@ bool DisplayConfigurator::SetDisplayPower(
native_display_delegate_->UngrabServer();
if (attempted_change)
NotifyObservers(success, new_state);
return true;
return success;
}

bool DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {
Expand All @@ -501,8 +504,8 @@ bool DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {

native_display_delegate_->GrabServer();
UpdateCachedDisplays();
const bool success =
EnterStateOrFallBackToSoftwareMirroring(new_state, power_state_);
const bool success = EnterStateOrFallBackToSoftwareMirroring(
new_state, requested_power_state_);
native_display_delegate_->UngrabServer();

NotifyObservers(success, new_state);
Expand Down Expand Up @@ -542,7 +545,7 @@ void DisplayConfigurator::SuspendDisplays() {
// suspending. This shouldn't be very noticeable to the user since the
// backlight is off at this point, and doing this lets us resume directly
// into the "on" state, which greatly reduces resume times.
if (power_state_ == chromeos::DISPLAY_POWER_ALL_OFF) {
if (requested_power_state_ == chromeos::DISPLAY_POWER_ALL_OFF) {
SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
kSetDisplayPowerOnlyIfSingleInternalDisplay);

Expand All @@ -561,7 +564,7 @@ void DisplayConfigurator::ResumeDisplays() {
base::TimeDelta::FromMilliseconds(kResumeDelayMs),
base::Bind(base::IgnoreResult(&DisplayConfigurator::SetDisplayPower),
base::Unretained(this),
power_state_,
requested_power_state_,
kSetDisplayPowerForceProbe));
}

Expand Down Expand Up @@ -713,9 +716,10 @@ void DisplayConfigurator::ConfigureDisplays() {

native_display_delegate_->GrabServer();
UpdateCachedDisplays();
const MultipleDisplayState new_state = ChooseDisplayState(power_state_);
const bool success =
EnterStateOrFallBackToSoftwareMirroring(new_state, power_state_);
const MultipleDisplayState new_state = ChooseDisplayState(
requested_power_state_);
const bool success = EnterStateOrFallBackToSoftwareMirroring(
new_state, requested_power_state_);
native_display_delegate_->UngrabServer();

NotifyObservers(success, new_state);
Expand All @@ -741,7 +745,7 @@ bool DisplayConfigurator::EnterStateOrFallBackToSoftwareMirroring(
bool enable_software_mirroring = false;
if (!success && display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) {
if (display_state_ != MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED ||
power_state_ != power_state)
current_power_state_ != power_state)
EnterState(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, power_state);
enable_software_mirroring = success =
display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
Expand All @@ -759,6 +763,9 @@ bool DisplayConfigurator::EnterState(MultipleDisplayState display_state,
VLOG(1) << "EnterState: display=" << DisplayStateToString(display_state)
<< " power=" << DisplayPowerStateToString(power_state);

// Save the requested state so we'll try to use it next time even if we fail.
requested_power_state_ = power_state;

// Framebuffer dimensions.
gfx::Size size;

Expand Down Expand Up @@ -925,7 +932,7 @@ bool DisplayConfigurator::EnterState(MultipleDisplayState display_state,

if (all_succeeded) {
display_state_ = display_state;
power_state_ = power_state;
current_power_state_ = power_state;
framebuffer_size_ = size;
}
return all_succeeded;
Expand Down
14 changes: 10 additions & 4 deletions ui/display/chromeos/display_configurator.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ class DISPLAY_EXPORT DisplayConfigurator : public NativeDisplayObserver {
virtual ~DisplayConfigurator();

MultipleDisplayState display_state() const { return display_state_; }
chromeos::DisplayPowerState power_state() const { return power_state_; }
chromeos::DisplayPowerState requested_power_state() const {
return requested_power_state_;
}
const gfx::Size framebuffer_size() const { return framebuffer_size_; }
const std::vector<DisplayState>& cached_displays() const {
return cached_displays_;
Expand Down Expand Up @@ -174,7 +176,8 @@ class DISPLAY_EXPORT DisplayConfigurator : public NativeDisplayObserver {
// Called when powerd notifies us that some set of displays should be turned
// on or off. This requires enabling or disabling the CRTC associated with
// the display(s) in question so that the low power state is engaged.
// |flags| contains bitwise-or-ed kSetDisplayPower* values.
// |flags| contains bitwise-or-ed kSetDisplayPower* values. Returns true if
// the system successfully enters (or was already in) |power_state|.
bool SetDisplayPower(chromeos::DisplayPowerState power_state, int flags);

// Force switching the display mode to |new_state|. Returns false if
Expand Down Expand Up @@ -320,8 +323,11 @@ class DISPLAY_EXPORT DisplayConfigurator : public NativeDisplayObserver {

gfx::Size framebuffer_size_;

// The current power state.
chromeos::DisplayPowerState power_state_;
// The last-requested and current power state. These may differ if
// configuration fails: SetDisplayMode() needs the last-requested state while
// SetDisplayPower() needs the current state.
chromeos::DisplayPowerState requested_power_state_;
chromeos::DisplayPowerState current_power_state_;

// Most-recently-used display configuration. Note that the actual
// configuration changes asynchronously.
Expand Down
40 changes: 38 additions & 2 deletions ui/display/chromeos/display_configurator_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1233,8 +1233,6 @@ TEST_F(DisplayConfiguratorTest, HandleConfigureCrtcFailure) {
outputs_[i].set_native_mode(modes[0]);
}

configurator_.Init(false);

// First test simply fails in MULTIPLE_DISPLAY_STATE_SINGLE mode. This is
// probably unrealistic but we want to make sure any assumptions don't creep
// in.
Expand Down Expand Up @@ -1302,4 +1300,42 @@ TEST_F(DisplayConfiguratorTest, HandleConfigureCrtcFailure) {
log_->GetActionsAndClear());
}

// Tests that power state requests are saved after failed configuration attempts
// so they can be reused later: http://crosbug.com/p/31571
TEST_F(DisplayConfiguratorTest, SaveDisplayPowerStateOnConfigFailure) {
// Start out with two displays in extended mode.
state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED);
configurator_.Init(false);
configurator_.ForceInitialConfigure(0);
log_->GetActionsAndClear();

// Turn off the internal display, simulating docked mode.
EXPECT_TRUE(configurator_.SetDisplayPower(
chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
DisplayConfigurator::kSetDisplayPowerNoFlags));
log_->GetActionsAndClear();

// Make all subsequent configuration requests fail and try to turn the
// internal display back on.
native_display_delegate_->set_max_configurable_pixels(1);
EXPECT_FALSE(configurator_.SetDisplayPower(
chromeos::DISPLAY_POWER_ALL_ON,
DisplayConfigurator::kSetDisplayPowerNoFlags));
log_->GetActionsAndClear();

// Simulate the external display getting disconnected and check that the
// internal display is turned on (i.e. DISPLAY_POWER_ALL_ON is used) rather
// than the earlier DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON state.
native_display_delegate_->set_max_configurable_pixels(0);
UpdateOutputs(1, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
}

} // namespace ui

0 comments on commit 4a06278

Please sign in to comment.