summaryrefslogtreecommitdiffstats
path: root/chromeos
diff options
context:
space:
mode:
authoroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-22 17:27:45 +0000
committeroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-22 17:27:45 +0000
commitc1f30dca390541354298d9db9f2571a50f569155 (patch)
tree58a875a3b128356962ddf8ab47f473da238846e4 /chromeos
parent7a44f9872eb3acf2acd6e25a3889bc42548e1d1f (diff)
downloadchromium_src-c1f30dca390541354298d9db9f2571a50f569155.zip
chromium_src-c1f30dca390541354298d9db9f2571a50f569155.tar.gz
chromium_src-c1f30dca390541354298d9db9f2571a50f569155.tar.bz2
This is a subset CL of the crrev.com/14731027, and
counter part is crrev.com/15367003. I'll send another CL that hooks them once both are landed. * Add SoftwareMirroringController that implements software based mirroring. * EnterStateOrFallbackToSoftwareMirroring will try to fallback software mirroring if the hardware based mirroring failed. BUG=239776 TEST=covered by test Review URL: https://chromiumcodereview.appspot.com/15448004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@201554 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos')
-rw-r--r--chromeos/display/output_configurator.cc31
-rw-r--r--chromeos/display/output_configurator.h23
-rw-r--r--chromeos/display/output_configurator_unittest.cc143
3 files changed, 193 insertions, 4 deletions
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc
index 44c4053..8214d0c 100644
--- a/chromeos/display/output_configurator.cc
+++ b/chromeos/display/output_configurator.cc
@@ -160,6 +160,7 @@ bool OutputConfigurator::TestApi::SendOutputChangeEvents(bool connected) {
OutputConfigurator::OutputConfigurator()
: state_controller_(NULL),
+ mirroring_controller_(NULL),
configure_display_(base::chromeos::IsRunningOnChromeOS()),
xrandr_event_base_(0),
output_state_(STATE_INVALID),
@@ -204,7 +205,8 @@ void OutputConfigurator::Start() {
delegate_->InitXRandRExtension(&xrandr_event_base_);
std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
- EnterState(GetOutputState(outputs, power_state_), power_state_, outputs);
+ EnterStateOrFallBackToSoftwareMirroring(
+ GetOutputState(outputs, power_state_), power_state_, outputs);
// Force the DPMS on chrome startup as the driver doesn't always detect
// that all displays are on when signing out.
@@ -234,7 +236,8 @@ bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state,
flags & kSetDisplayPowerOnlyIfSingleInternalDisplay;
bool single_internal_display = outputs.size() == 1 && outputs[0].is_internal;
if ((single_internal_display || !only_if_single_internal_display) &&
- EnterState(GetOutputState(outputs, power_state), power_state, outputs)) {
+ EnterStateOrFallBackToSoftwareMirroring(
+ GetOutputState(outputs, power_state), power_state, outputs)) {
if (power_state != DISPLAY_POWER_ALL_OFF) {
// Force the DPMS on since the driver doesn't always detect that it
// should turn on. This is needed when coming back from idle suspend.
@@ -256,7 +259,8 @@ bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
delegate_->GrabServer();
std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
- bool success = EnterState(new_state, power_state_, outputs);
+ bool success = EnterStateOrFallBackToSoftwareMirroring(
+ new_state, power_state_, outputs);
delegate_->UngrabServer();
if (success) {
@@ -344,7 +348,8 @@ void OutputConfigurator::ConfigureOutputs() {
delegate_->GrabServer();
std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
OutputState new_state = GetOutputState(outputs, power_state_);
- bool success = EnterState(new_state, power_state_, outputs);
+ bool success = EnterStateOrFallBackToSoftwareMirroring(
+ new_state, power_state_, outputs);
delegate_->UngrabServer();
if (success) {
@@ -360,6 +365,24 @@ void OutputConfigurator::NotifyOnDisplayChanged() {
FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
}
+bool OutputConfigurator::EnterStateOrFallBackToSoftwareMirroring(
+ OutputState output_state,
+ DisplayPowerState power_state,
+ const std::vector<OutputSnapshot>& outputs) {
+ bool success = EnterState(output_state, power_state, outputs);
+ if (mirroring_controller_) {
+ bool enable_software_mirroring = false;
+ if (!success && output_state == STATE_DUAL_MIRROR) {
+ if (output_state_ != STATE_DUAL_EXTENDED || power_state_ != power_state)
+ EnterState(STATE_DUAL_EXTENDED, power_state, outputs);
+ enable_software_mirroring = success =
+ output_state_ == STATE_DUAL_EXTENDED;
+ }
+ mirroring_controller_->SetSoftwareMirroring(enable_software_mirroring);
+ }
+ return success;
+}
+
bool OutputConfigurator::EnterState(
OutputState output_state,
DisplayPowerState power_state,
diff --git a/chromeos/display/output_configurator.h b/chromeos/display/output_configurator.h
index 84de2d0..96c38b3 100644
--- a/chromeos/display/output_configurator.h
+++ b/chromeos/display/output_configurator.h
@@ -114,6 +114,15 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
const std::vector<int64>& display_ids) const = 0;
};
+ // Interface for classes that implement software based mirroring.
+ class SoftwareMirroringController {
+ public:
+ virtual ~SoftwareMirroringController() {}
+
+ // Called when the hardware mirroring failed.
+ virtual void SetSoftwareMirroring(bool enabled) = 0;
+ };
+
// Interface for classes that perform actions on behalf of OutputController.
class Delegate {
public:
@@ -227,6 +236,9 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
void set_state_controller(StateController* controller) {
state_controller_ = controller;
}
+ void set_mirroring_controller(SoftwareMirroringController* controller) {
+ mirroring_controller_ = controller;
+ }
// Replaces |delegate_| with |delegate| and sets |configure_display_| to
// true. Should be called before Init().
@@ -290,6 +302,16 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
void NotifyOnDisplayChanged();
// Switches to the state specified in |output_state| and |power_state|.
+ // If the hardware mirroring failed and |mirroring_controller_| is set,
+ // it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()|
+ // to enable software based mirroing.
+ // On success, updates |output_state_| and |power_state_| and returns true.
+ bool EnterStateOrFallBackToSoftwareMirroring(
+ OutputState output_state,
+ DisplayPowerState power_state,
+ const std::vector<OutputSnapshot>& outputs);
+
+ // Switches to the state specified in |output_state| and |power_state|.
// On success, updates |output_state_| and |power_state_| and returns true.
bool EnterState(OutputState output_state,
DisplayPowerState power_state,
@@ -312,6 +334,7 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
const OutputConfigurator::OutputSnapshot* output);
StateController* state_controller_;
+ SoftwareMirroringController* mirroring_controller_;
scoped_ptr<Delegate> delegate_;
// Key of the map is the touch display's id, and the value of the map is the
diff --git a/chromeos/display/output_configurator_unittest.cc b/chromeos/display/output_configurator_unittest.cc
index 8f69ce7..606180c 100644
--- a/chromeos/display/output_configurator_unittest.cc
+++ b/chromeos/display/output_configurator_unittest.cc
@@ -217,6 +217,26 @@ class TestStateController : public OutputConfigurator::StateController {
DISALLOW_COPY_AND_ASSIGN(TestStateController);
};
+class TestMirroringController
+ : public OutputConfigurator::SoftwareMirroringController {
+ public:
+ TestMirroringController() : software_mirroring_enabled_(false) {}
+ virtual ~TestMirroringController() {}
+
+ virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
+ software_mirroring_enabled_ = enabled;
+ }
+
+ bool software_mirroring_enabled() const {
+ return software_mirroring_enabled_;
+ }
+
+ private:
+ bool software_mirroring_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
+};
+
class OutputConfiguratorTest : public testing::Test {
public:
OutputConfiguratorTest()
@@ -228,6 +248,7 @@ class OutputConfiguratorTest : public testing::Test {
configurator_.SetDelegateForTesting(
scoped_ptr<OutputConfigurator::Delegate>(delegate_));
configurator_.set_state_controller(&state_controller_);
+ configurator_.set_mirroring_controller(&mirroring_controller_);
OutputConfigurator::OutputSnapshot* o = &outputs_[0];
o->output = 1;
@@ -260,6 +281,10 @@ class OutputConfiguratorTest : public testing::Test {
delegate_->AddMode(kBigModeId, kBigModeWidth, kBigModeHeight, false);
}
+ void DisableNativeMirroring() {
+ outputs_[0].mirror_mode = outputs_[1].mirror_mode = 0L;
+ }
+
protected:
// Predefined modes that can be used by outputs.
static const int kSmallModeId = 20;
@@ -299,6 +324,7 @@ class OutputConfiguratorTest : public testing::Test {
base::MessageLoop message_loop_;
TestStateController state_controller_;
+ TestMirroringController mirroring_controller_;
OutputConfigurator configurator_;
TestDelegate* delegate_; // not owned
OutputConfigurator::TestApi test_api_;
@@ -331,6 +357,7 @@ TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
kBigModeId, outputs_[1].output).c_str(),
kUngrab, kProjectingOn, NULL),
delegate_->GetActionsAndClear());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
EXPECT_EQ(JoinActions(kGrab,
@@ -342,6 +369,7 @@ TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
outputs_[1].output).c_str(),
kUngrab, NULL),
delegate_->GetActionsAndClear());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
// Disconnect the second output.
UpdateOutputs(1);
@@ -353,6 +381,42 @@ TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
outputs_[0].output).c_str(),
kUngrab, kProjectingOff, NULL),
delegate_->GetActionsAndClear());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+
+ // Software Mirroring
+ DisableNativeMirroring();
+ UpdateOutputs(2);
+ state_controller_.set_state(STATE_DUAL_EXTENDED);
+ EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
+ EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
+ GetFramebufferAction(kBigModeWidth, kDualHeight,
+ outputs_[0].crtc, outputs_[1].crtc).c_str(),
+ GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+ outputs_[0].output).c_str(),
+ GetCrtcAction(outputs_[1].crtc, 0,
+ kSmallModeHeight + OutputConfigurator::kVerticalGap,
+ kBigModeId, outputs_[1].output).c_str(),
+ kUngrab, kProjectingOn, NULL),
+ delegate_->GetActionsAndClear());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+
+ EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
+ EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
+ delegate_->GetActionsAndClear());
+ EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
+ EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
+
+ // Disconnect the second output.
+ UpdateOutputs(1);
+ EXPECT_TRUE(test_api_.SendOutputChangeEvents(false));
+ EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
+ GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
+ outputs_[0].crtc, 0).c_str(),
+ GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+ outputs_[0].output).c_str(),
+ kUngrab, kProjectingOff, NULL),
+ delegate_->GetActionsAndClear());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
}
TEST_F(OutputConfiguratorTest, SetDisplayPower) {
@@ -370,6 +434,7 @@ TEST_F(OutputConfiguratorTest, SetDisplayPower) {
outputs_[1].output).c_str(),
kUngrab, kProjectingOn, NULL),
delegate_->GetActionsAndClear());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
// Turning off the internal display should switch the external display to
// its native mode.
@@ -384,6 +449,7 @@ TEST_F(OutputConfiguratorTest, SetDisplayPower) {
outputs_[1].output).c_str(),
kForceDPMS, kUngrab, NULL),
delegate_->GetActionsAndClear());
+ EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
// When all displays are turned off, the framebuffer should switch back
// to the mirrored size.
@@ -398,6 +464,8 @@ TEST_F(OutputConfiguratorTest, SetDisplayPower) {
outputs_[1].output).c_str(),
kUngrab, NULL),
delegate_->GetActionsAndClear());
+ EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
// Turn all displays on and check that mirroring is still used.
configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
@@ -411,6 +479,81 @@ TEST_F(OutputConfiguratorTest, SetDisplayPower) {
outputs_[1].output).c_str(),
kForceDPMS, kUngrab, NULL),
delegate_->GetActionsAndClear());
+ EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+
+ // Software Mirroring
+ DisableNativeMirroring();
+ UpdateOutputs(2);
+
+ const int kDualHeight =
+ kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
+
+ state_controller_.set_state(STATE_DUAL_MIRROR);
+ EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
+ // Move to extended
+ EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
+ GetFramebufferAction(kBigModeWidth, kDualHeight,
+ outputs_[0].crtc, outputs_[1].crtc).c_str(),
+ GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+ outputs_[0].output).c_str(),
+ GetCrtcAction(outputs_[1].crtc, 0,
+ kSmallModeHeight + OutputConfigurator::kVerticalGap,
+ kBigModeId, outputs_[1].output).c_str(),
+ kUngrab, kProjectingOn, NULL),
+ delegate_->GetActionsAndClear());
+ EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
+ EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
+
+ // Turning off the internal display should switch the external display to
+ // its native mode.
+ configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
+ OutputConfigurator::kSetDisplayPowerNoFlags);
+ EXPECT_EQ(JoinActions(kGrab,
+ GetFramebufferAction(kBigModeWidth, kBigModeHeight,
+ outputs_[0].crtc, outputs_[1].crtc).c_str(),
+ GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
+ outputs_[0].output).c_str(),
+ GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
+ outputs_[1].output).c_str(),
+ kForceDPMS, kUngrab, NULL),
+ delegate_->GetActionsAndClear());
+ EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
+ EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+
+ // When all displays are turned off, the framebuffer should switch back
+ // to the extended + software mirroring.
+ configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
+ OutputConfigurator::kSetDisplayPowerNoFlags);
+ EXPECT_EQ(JoinActions(kGrab,
+ GetFramebufferAction(kBigModeWidth, kDualHeight,
+ outputs_[0].crtc, outputs_[1].crtc).c_str(),
+ GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
+ outputs_[0].output).c_str(),
+ GetCrtcAction(outputs_[1].crtc, 0,
+ kSmallModeHeight + OutputConfigurator::kVerticalGap,
+ 0, outputs_[1].output).c_str(),
+ kUngrab, NULL),
+ delegate_->GetActionsAndClear());
+ EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
+ EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
+
+ // Turn all displays on and check that mirroring is still used.
+ configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
+ OutputConfigurator::kSetDisplayPowerNoFlags);
+ EXPECT_EQ(JoinActions(kGrab,
+ GetFramebufferAction(kBigModeWidth, kDualHeight,
+ outputs_[0].crtc, outputs_[1].crtc).c_str(),
+ GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+ outputs_[0].output).c_str(),
+ GetCrtcAction(outputs_[1].crtc, 0,
+ kSmallModeHeight + OutputConfigurator::kVerticalGap,
+ kBigModeId, outputs_[1].output).c_str(),
+ kForceDPMS, kUngrab, NULL),
+ delegate_->GetActionsAndClear());
+ EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
+ EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
+
}
TEST_F(OutputConfiguratorTest, SuspendAndResume) {