| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/display/chromeos/display_configurator.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include "base/macros.h" | |
| 11 #include "base/memory/ptr_util.h" | |
| 12 #include "base/memory/scoped_vector.h" | |
| 13 #include "base/message_loop/message_loop.h" | |
| 14 #include "base/run_loop.h" | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | |
| 16 #include "ui/display/chromeos/test/action_logger_util.h" | |
| 17 #include "ui/display/chromeos/test/test_native_display_delegate.h" | |
| 18 #include "ui/display/fake_display_snapshot.h" | |
| 19 #include "ui/display/util/display_util.h" | |
| 20 | |
| 21 namespace ui { | |
| 22 namespace test { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 int64_t kDisplayIds[3] = {123, 456, 789}; | |
| 27 | |
| 28 std::unique_ptr<ui::DisplayMode> MakeDisplayMode(int width, | |
| 29 int height, | |
| 30 bool is_interlaced, | |
| 31 float refresh_rate) { | |
| 32 return base::MakeUnique<ui::DisplayMode>(gfx::Size(width, height), | |
| 33 is_interlaced, refresh_rate); | |
| 34 } | |
| 35 | |
| 36 enum CallbackResult { | |
| 37 CALLBACK_FAILURE, | |
| 38 CALLBACK_SUCCESS, | |
| 39 CALLBACK_NOT_CALLED, | |
| 40 }; | |
| 41 | |
| 42 // Expected immediate configurations should be done without any delays. | |
| 43 constexpr base::TimeDelta kNoDelay = base::TimeDelta::FromMilliseconds(0); | |
| 44 | |
| 45 // The expected configuration delay when resuming from suspend while in 2+ | |
| 46 // display mode. | |
| 47 constexpr base::TimeDelta kLongDelay = base::TimeDelta::FromMilliseconds( | |
| 48 DisplayConfigurator::kResumeConfigureMultiDisplayDelayMs); | |
| 49 | |
| 50 class TestObserver : public DisplayConfigurator::Observer { | |
| 51 public: | |
| 52 explicit TestObserver(DisplayConfigurator* configurator) | |
| 53 : configurator_(configurator) { | |
| 54 Reset(); | |
| 55 configurator_->AddObserver(this); | |
| 56 } | |
| 57 ~TestObserver() override { configurator_->RemoveObserver(this); } | |
| 58 | |
| 59 int num_changes() const { return num_changes_; } | |
| 60 int num_failures() const { return num_failures_; } | |
| 61 const DisplayConfigurator::DisplayStateList& latest_outputs() const { | |
| 62 return latest_outputs_; | |
| 63 } | |
| 64 MultipleDisplayState latest_failed_state() const { | |
| 65 return latest_failed_state_; | |
| 66 } | |
| 67 | |
| 68 void Reset() { | |
| 69 num_changes_ = 0; | |
| 70 num_failures_ = 0; | |
| 71 latest_outputs_.clear(); | |
| 72 latest_failed_state_ = MULTIPLE_DISPLAY_STATE_INVALID; | |
| 73 } | |
| 74 | |
| 75 // DisplayConfigurator::Observer overrides: | |
| 76 void OnDisplayModeChanged( | |
| 77 const DisplayConfigurator::DisplayStateList& outputs) override { | |
| 78 num_changes_++; | |
| 79 latest_outputs_ = outputs; | |
| 80 } | |
| 81 | |
| 82 void OnDisplayModeChangeFailed( | |
| 83 const DisplayConfigurator::DisplayStateList& outputs, | |
| 84 MultipleDisplayState failed_new_state) override { | |
| 85 num_failures_++; | |
| 86 latest_failed_state_ = failed_new_state; | |
| 87 } | |
| 88 | |
| 89 private: | |
| 90 DisplayConfigurator* configurator_; // Not owned. | |
| 91 | |
| 92 // Number of times that OnDisplayMode*() has been called. | |
| 93 int num_changes_; | |
| 94 int num_failures_; | |
| 95 | |
| 96 // Parameters most recently passed to OnDisplayMode*(). | |
| 97 DisplayConfigurator::DisplayStateList latest_outputs_; | |
| 98 MultipleDisplayState latest_failed_state_; | |
| 99 | |
| 100 DISALLOW_COPY_AND_ASSIGN(TestObserver); | |
| 101 }; | |
| 102 | |
| 103 class TestStateController : public DisplayConfigurator::StateController { | |
| 104 public: | |
| 105 TestStateController() : state_(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) {} | |
| 106 ~TestStateController() override {} | |
| 107 | |
| 108 void set_state(MultipleDisplayState state) { state_ = state; } | |
| 109 | |
| 110 // DisplayConfigurator::StateController overrides: | |
| 111 MultipleDisplayState GetStateForDisplayIds( | |
| 112 const DisplayConfigurator::DisplayStateList& outputs) const override { | |
| 113 return state_; | |
| 114 } | |
| 115 bool GetResolutionForDisplayId(int64_t display_id, | |
| 116 gfx::Size* size) const override { | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 120 private: | |
| 121 MultipleDisplayState state_; | |
| 122 | |
| 123 DISALLOW_COPY_AND_ASSIGN(TestStateController); | |
| 124 }; | |
| 125 | |
| 126 class TestMirroringController | |
| 127 : public DisplayConfigurator::SoftwareMirroringController { | |
| 128 public: | |
| 129 TestMirroringController() : software_mirroring_enabled_(false) {} | |
| 130 ~TestMirroringController() override {} | |
| 131 | |
| 132 void SetSoftwareMirroring(bool enabled) override { | |
| 133 software_mirroring_enabled_ = enabled; | |
| 134 } | |
| 135 | |
| 136 bool SoftwareMirroringEnabled() const override { | |
| 137 return software_mirroring_enabled_; | |
| 138 } | |
| 139 | |
| 140 private: | |
| 141 bool software_mirroring_enabled_; | |
| 142 | |
| 143 DISALLOW_COPY_AND_ASSIGN(TestMirroringController); | |
| 144 }; | |
| 145 | |
| 146 // Abstracts waiting for the display configuration to be completed and getting | |
| 147 // the time it took to complete. | |
| 148 class ConfigurationWaiter { | |
| 149 public: | |
| 150 ConfigurationWaiter(DisplayConfigurator::TestApi* test_api) | |
| 151 : on_configured_callback_(base::Bind(&ConfigurationWaiter::OnConfigured, | |
| 152 base::Unretained(this))), | |
| 153 test_api_(test_api), | |
| 154 callback_result_(CALLBACK_NOT_CALLED) {} | |
| 155 | |
| 156 ~ConfigurationWaiter() = default; | |
| 157 | |
| 158 const DisplayConfigurator::ConfigurationCallback& on_configuration_callback() | |
| 159 const { | |
| 160 return on_configured_callback_; | |
| 161 } | |
| 162 | |
| 163 CallbackResult callback_result() const { return callback_result_; } | |
| 164 | |
| 165 void Reset() { callback_result_ = CALLBACK_NOT_CALLED; } | |
| 166 | |
| 167 // Simulates waiting for the next configuration. If an async task is pending, | |
| 168 // runs it and returns base::TimeDelta(). Otherwise, triggers the | |
| 169 // configuration timer and returns its delay. If the timer wasn't running, | |
| 170 // returns base::TimeDelta::Max(). | |
| 171 base::TimeDelta Wait() WARN_UNUSED_RESULT { | |
| 172 base::RunLoop().RunUntilIdle(); | |
| 173 if (callback_result_ != CALLBACK_NOT_CALLED) | |
| 174 return base::TimeDelta(); | |
| 175 | |
| 176 const base::TimeDelta delay = test_api_->GetConfigureDelay(); | |
| 177 if (!test_api_->TriggerConfigureTimeout()) | |
| 178 return base::TimeDelta::Max(); | |
| 179 | |
| 180 return delay; | |
| 181 } | |
| 182 | |
| 183 private: | |
| 184 void OnConfigured(bool status) { | |
| 185 CHECK_EQ(callback_result_, CALLBACK_NOT_CALLED); | |
| 186 callback_result_ = status ? CALLBACK_SUCCESS : CALLBACK_FAILURE; | |
| 187 } | |
| 188 | |
| 189 // Passed with configuration requests to run OnConfigured(). | |
| 190 const DisplayConfigurator::ConfigurationCallback on_configured_callback_; | |
| 191 | |
| 192 DisplayConfigurator::TestApi* test_api_; // Not owned. | |
| 193 | |
| 194 // The status of the display configuration. | |
| 195 CallbackResult callback_result_; | |
| 196 | |
| 197 DISALLOW_COPY_AND_ASSIGN(ConfigurationWaiter); | |
| 198 }; | |
| 199 | |
| 200 class DisplayConfiguratorTest : public testing::Test { | |
| 201 public: | |
| 202 DisplayConfiguratorTest() | |
| 203 : small_mode_(gfx::Size(1366, 768), false, 60.0f), | |
| 204 big_mode_(gfx::Size(2560, 1600), false, 60.0f), | |
| 205 observer_(&configurator_), | |
| 206 test_api_(&configurator_), | |
| 207 config_waiter_(&test_api_), | |
| 208 enable_content_protection_status_(0), | |
| 209 enable_content_protection_call_count_(0), | |
| 210 query_content_protection_call_count_(0), | |
| 211 display_control_result_(CALLBACK_NOT_CALLED) {} | |
| 212 ~DisplayConfiguratorTest() override {} | |
| 213 | |
| 214 void SetUp() override { | |
| 215 log_.reset(new ActionLogger()); | |
| 216 | |
| 217 native_display_delegate_ = new TestNativeDisplayDelegate(log_.get()); | |
| 218 configurator_.SetDelegateForTesting( | |
| 219 std::unique_ptr<NativeDisplayDelegate>(native_display_delegate_)); | |
| 220 | |
| 221 configurator_.set_state_controller(&state_controller_); | |
| 222 configurator_.set_mirroring_controller(&mirroring_controller_); | |
| 223 | |
| 224 outputs_[0] = display::FakeDisplaySnapshot::Builder() | |
| 225 .SetId(kDisplayIds[0]) | |
| 226 .SetNativeMode(small_mode_.Clone()) | |
| 227 .SetCurrentMode(small_mode_.Clone()) | |
| 228 .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL) | |
| 229 .SetIsAspectPerservingScaling(true) | |
| 230 .Build(); | |
| 231 | |
| 232 outputs_[1] = display::FakeDisplaySnapshot::Builder() | |
| 233 .SetId(kDisplayIds[1]) | |
| 234 .SetNativeMode(big_mode_.Clone()) | |
| 235 .SetCurrentMode(big_mode_.Clone()) | |
| 236 .AddMode(small_mode_.Clone()) | |
| 237 .SetType(DISPLAY_CONNECTION_TYPE_HDMI) | |
| 238 .SetIsAspectPerservingScaling(true) | |
| 239 .Build(); | |
| 240 | |
| 241 outputs_[2] = display::FakeDisplaySnapshot::Builder() | |
| 242 .SetId(kDisplayIds[2]) | |
| 243 .SetNativeMode(small_mode_.Clone()) | |
| 244 .SetCurrentMode(small_mode_.Clone()) | |
| 245 .SetType(DISPLAY_CONNECTION_TYPE_HDMI) | |
| 246 .SetIsAspectPerservingScaling(true) | |
| 247 .Build(); | |
| 248 | |
| 249 UpdateOutputs(2, false); | |
| 250 } | |
| 251 | |
| 252 void OnDisplayControlUpdated(bool status) { | |
| 253 display_control_result_ = (status ? CALLBACK_SUCCESS : CALLBACK_FAILURE); | |
| 254 } | |
| 255 | |
| 256 void EnableContentProtectionCallback(bool status) { | |
| 257 enable_content_protection_status_ = status; | |
| 258 enable_content_protection_call_count_++; | |
| 259 } | |
| 260 | |
| 261 void QueryContentProtectionCallback( | |
| 262 const DisplayConfigurator::QueryProtectionResponse& response) { | |
| 263 query_content_protection_response_ = response; | |
| 264 query_content_protection_call_count_++; | |
| 265 } | |
| 266 | |
| 267 // Predefined modes that can be used by outputs. | |
| 268 const DisplayMode small_mode_; | |
| 269 const DisplayMode big_mode_; | |
| 270 | |
| 271 protected: | |
| 272 // Configures |native_display_delegate_| to return the first |num_outputs| | |
| 273 // entries from | |
| 274 // |outputs_|. If |send_events| is true, also sends screen-change and | |
| 275 // output-change events to |configurator_| and triggers the configure | |
| 276 // timeout if one was scheduled. | |
| 277 void UpdateOutputs(size_t num_outputs, bool send_events) { | |
| 278 ASSERT_LE(num_outputs, arraysize(outputs_)); | |
| 279 std::vector<DisplaySnapshot*> outputs; | |
| 280 for (size_t i = 0; i < num_outputs; ++i) | |
| 281 outputs.push_back(outputs_[i].get()); | |
| 282 native_display_delegate_->set_outputs(outputs); | |
| 283 | |
| 284 if (send_events) { | |
| 285 configurator_.OnConfigurationChanged(); | |
| 286 EXPECT_TRUE(test_api_.TriggerConfigureTimeout()); | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 void Init(bool panel_fitting_enabled) { | |
| 291 configurator_.Init(nullptr, panel_fitting_enabled); | |
| 292 } | |
| 293 | |
| 294 // Initializes |configurator_| with a single internal display. | |
| 295 void InitWithSingleOutput() { | |
| 296 UpdateOutputs(1, false); | |
| 297 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 298 configurator_.Init(nullptr, false); | |
| 299 | |
| 300 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 301 configurator_.ForceInitialConfigure(0); | |
| 302 EXPECT_EQ( | |
| 303 JoinActions( | |
| 304 kInitXRandR, kGrab, | |
| 305 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 306 .c_str(), | |
| 307 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 308 kForceDPMS, kUngrab, nullptr), | |
| 309 log_->GetActionsAndClear()); | |
| 310 } | |
| 311 | |
| 312 CallbackResult PopDisplayControlResult() { | |
| 313 CallbackResult result = display_control_result_; | |
| 314 display_control_result_ = CALLBACK_NOT_CALLED; | |
| 315 return result; | |
| 316 } | |
| 317 | |
| 318 base::MessageLoop message_loop_; | |
| 319 TestStateController state_controller_; | |
| 320 TestMirroringController mirroring_controller_; | |
| 321 DisplayConfigurator configurator_; | |
| 322 TestObserver observer_; | |
| 323 std::unique_ptr<ActionLogger> log_; | |
| 324 TestNativeDisplayDelegate* native_display_delegate_; // not owned | |
| 325 DisplayConfigurator::TestApi test_api_; | |
| 326 ConfigurationWaiter config_waiter_; | |
| 327 bool enable_content_protection_status_; | |
| 328 int enable_content_protection_call_count_; | |
| 329 DisplayConfigurator::QueryProtectionResponse | |
| 330 query_content_protection_response_; | |
| 331 int query_content_protection_call_count_; | |
| 332 | |
| 333 std::unique_ptr<DisplaySnapshot> outputs_[3]; | |
| 334 | |
| 335 CallbackResult display_control_result_; | |
| 336 | |
| 337 private: | |
| 338 DISALLOW_COPY_AND_ASSIGN(DisplayConfiguratorTest); | |
| 339 }; | |
| 340 | |
| 341 } // namespace | |
| 342 | |
| 343 TEST_F(DisplayConfiguratorTest, FindDisplayModeMatchingSize) { | |
| 344 std::unique_ptr<ui::DisplaySnapshot> output = | |
| 345 display::FakeDisplaySnapshot::Builder() | |
| 346 .SetId(kDisplayIds[0]) | |
| 347 .AddMode(MakeDisplayMode(1920, 1200, false, 60.0)) | |
| 348 .SetNativeMode(MakeDisplayMode(1920, 1200, false, 50.0)) | |
| 349 // Different rates. | |
| 350 .AddMode(MakeDisplayMode(1920, 1080, false, 30.0)) | |
| 351 .AddMode(MakeDisplayMode(1920, 1080, false, 50.0)) | |
| 352 .AddMode(MakeDisplayMode(1920, 1080, false, 40.0)) | |
| 353 .AddMode(MakeDisplayMode(1920, 1080, false, 0.0)) | |
| 354 // Interlaced vs non-interlaced. | |
| 355 .AddMode(MakeDisplayMode(1280, 720, true, 60.0)) | |
| 356 .AddMode(MakeDisplayMode(1280, 720, false, 40.0)) | |
| 357 // Interlaced only. | |
| 358 .AddMode(MakeDisplayMode(1024, 768, true, 0.0)) | |
| 359 .AddMode(MakeDisplayMode(1024, 768, true, 40.0)) | |
| 360 .AddMode(MakeDisplayMode(1024, 768, true, 60.0)) | |
| 361 // Mixed. | |
| 362 .AddMode(MakeDisplayMode(1024, 600, true, 60.0)) | |
| 363 .AddMode(MakeDisplayMode(1024, 600, false, 40.0)) | |
| 364 .AddMode(MakeDisplayMode(1024, 600, false, 50.0)) | |
| 365 // Just one interlaced mode. | |
| 366 .AddMode(MakeDisplayMode(640, 480, true, 60.0)) | |
| 367 // Refresh rate not available. | |
| 368 .AddMode(MakeDisplayMode(320, 200, false, 0.0)) | |
| 369 .Build(); | |
| 370 | |
| 371 const std::vector<std::unique_ptr<const DisplayMode>>& modes = | |
| 372 output->modes(); | |
| 373 | |
| 374 // Should pick native over highest refresh rate. | |
| 375 EXPECT_EQ(modes[1].get(), DisplayConfigurator::FindDisplayModeMatchingSize( | |
| 376 *output, gfx::Size(1920, 1200))); | |
| 377 | |
| 378 // Should pick highest refresh rate. | |
| 379 EXPECT_EQ(modes[3].get(), DisplayConfigurator::FindDisplayModeMatchingSize( | |
| 380 *output, gfx::Size(1920, 1080))); | |
| 381 | |
| 382 // Should pick non-interlaced mode. | |
| 383 EXPECT_EQ(modes[7].get(), DisplayConfigurator::FindDisplayModeMatchingSize( | |
| 384 *output, gfx::Size(1280, 720))); | |
| 385 | |
| 386 // Interlaced only. Should pick one with the highest refresh rate in | |
| 387 // interlaced mode. | |
| 388 EXPECT_EQ(modes[10].get(), DisplayConfigurator::FindDisplayModeMatchingSize( | |
| 389 *output, gfx::Size(1024, 768))); | |
| 390 | |
| 391 // Mixed: Should pick one with the highest refresh rate in | |
| 392 // interlaced mode. | |
| 393 EXPECT_EQ(modes[13].get(), DisplayConfigurator::FindDisplayModeMatchingSize( | |
| 394 *output, gfx::Size(1024, 600))); | |
| 395 | |
| 396 // Just one interlaced mode. | |
| 397 EXPECT_EQ(modes[14].get(), DisplayConfigurator::FindDisplayModeMatchingSize( | |
| 398 *output, gfx::Size(640, 480))); | |
| 399 | |
| 400 // Refresh rate not available. | |
| 401 EXPECT_EQ(modes[15].get(), DisplayConfigurator::FindDisplayModeMatchingSize( | |
| 402 *output, gfx::Size(320, 200))); | |
| 403 | |
| 404 // No mode found. | |
| 405 EXPECT_EQ(nullptr, DisplayConfigurator::FindDisplayModeMatchingSize( | |
| 406 *output, gfx::Size(1440, 900))); | |
| 407 } | |
| 408 | |
| 409 TEST_F(DisplayConfiguratorTest, EnableVirtualDisplay) { | |
| 410 InitWithSingleOutput(); | |
| 411 | |
| 412 observer_.Reset(); | |
| 413 const DisplayConfigurator::DisplayStateList& cached = | |
| 414 configurator_.cached_displays(); | |
| 415 ASSERT_EQ(static_cast<size_t>(1u), cached.size()); | |
| 416 EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | |
| 417 | |
| 418 // Add virtual display. | |
| 419 int64_t virtual_display_id = | |
| 420 configurator_.AddVirtualDisplay(big_mode_.size()); | |
| 421 EXPECT_EQ(display::GenerateDisplayID(0x8000, 0x0, 1), virtual_display_id); | |
| 422 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 423 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 424 configurator_.display_state()); | |
| 425 | |
| 426 // Virtual should not trigger addition of added crtc but does change FB | |
| 427 // height. | |
| 428 const int kVirtualHeight = small_mode_.size().height() + | |
| 429 DisplayConfigurator::kVerticalGap + | |
| 430 big_mode_.size().height(); | |
| 431 EXPECT_EQ( | |
| 432 JoinActions( | |
| 433 kGrab, GetFramebufferAction( | |
| 434 gfx::Size(big_mode_.size().width(), kVirtualHeight), | |
| 435 outputs_[0].get(), nullptr) | |
| 436 .c_str(), | |
| 437 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 438 kUngrab, nullptr), | |
| 439 log_->GetActionsAndClear()); | |
| 440 EXPECT_EQ(1, observer_.num_changes()); | |
| 441 ASSERT_EQ(static_cast<size_t>(2u), cached.size()); | |
| 442 EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | |
| 443 EXPECT_EQ(big_mode_.size(), cached[1]->current_mode()->size()); | |
| 444 EXPECT_EQ(virtual_display_id, cached[1]->display_id()); | |
| 445 | |
| 446 // Remove virtual display. | |
| 447 observer_.Reset(); | |
| 448 EXPECT_TRUE(configurator_.RemoveVirtualDisplay(virtual_display_id)); | |
| 449 EXPECT_EQ( | |
| 450 JoinActions( | |
| 451 kGrab, | |
| 452 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 453 .c_str(), | |
| 454 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 455 kUngrab, nullptr), | |
| 456 log_->GetActionsAndClear()); | |
| 457 EXPECT_EQ(1, observer_.num_changes()); | |
| 458 ASSERT_EQ(static_cast<size_t>(1u), cached.size()); | |
| 459 EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | |
| 460 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state()); | |
| 461 } | |
| 462 | |
| 463 TEST_F(DisplayConfiguratorTest, EnableTwoVirtualDisplays) { | |
| 464 InitWithSingleOutput(); | |
| 465 | |
| 466 observer_.Reset(); | |
| 467 const DisplayConfigurator::DisplayStateList& cached = | |
| 468 configurator_.cached_displays(); | |
| 469 ASSERT_EQ(static_cast<size_t>(1u), cached.size()); | |
| 470 EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | |
| 471 | |
| 472 // Add 1st virtual display. | |
| 473 int64_t virtual_display_id_1 = | |
| 474 configurator_.AddVirtualDisplay(big_mode_.size()); | |
| 475 EXPECT_EQ(display::GenerateDisplayID(0x8000, 0x0, 1), virtual_display_id_1); | |
| 476 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 477 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 478 configurator_.display_state()); | |
| 479 | |
| 480 // Virtual should not trigger addition of added crtc but does change FB | |
| 481 // height. | |
| 482 const int kSingleVirtualHeight = small_mode_.size().height() + | |
| 483 DisplayConfigurator::kVerticalGap + | |
| 484 big_mode_.size().height(); | |
| 485 EXPECT_EQ( | |
| 486 JoinActions( | |
| 487 kGrab, GetFramebufferAction( | |
| 488 gfx::Size(big_mode_.size().width(), kSingleVirtualHeight), | |
| 489 outputs_[0].get(), nullptr) | |
| 490 .c_str(), | |
| 491 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 492 kUngrab, nullptr), | |
| 493 log_->GetActionsAndClear()); | |
| 494 EXPECT_EQ(1, observer_.num_changes()); | |
| 495 ASSERT_EQ(static_cast<size_t>(2), cached.size()); | |
| 496 EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | |
| 497 EXPECT_EQ(big_mode_.size(), cached[1]->current_mode()->size()); | |
| 498 EXPECT_EQ(virtual_display_id_1, cached[1]->display_id()); | |
| 499 | |
| 500 // Add 2nd virtual display | |
| 501 int64_t virtual_display_id_2 = | |
| 502 configurator_.AddVirtualDisplay(big_mode_.size()); | |
| 503 EXPECT_EQ(display::GenerateDisplayID(0x8000, 0x0, 2), virtual_display_id_2); | |
| 504 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 505 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, | |
| 506 configurator_.display_state()); | |
| 507 | |
| 508 const int kDualVirtualHeight = | |
| 509 small_mode_.size().height() + | |
| 510 (DisplayConfigurator::kVerticalGap + big_mode_.size().height()) * 2; | |
| 511 EXPECT_EQ( | |
| 512 JoinActions( | |
| 513 kGrab, GetFramebufferAction( | |
| 514 gfx::Size(big_mode_.size().width(), kDualVirtualHeight), | |
| 515 outputs_[0].get(), nullptr) | |
| 516 .c_str(), | |
| 517 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 518 kUngrab, nullptr), | |
| 519 log_->GetActionsAndClear()); | |
| 520 EXPECT_EQ(2, observer_.num_changes()); | |
| 521 ASSERT_EQ(static_cast<size_t>(3u), cached.size()); | |
| 522 EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | |
| 523 EXPECT_EQ(big_mode_.size(), cached[1]->current_mode()->size()); | |
| 524 EXPECT_EQ(big_mode_.size(), cached[2]->current_mode()->size()); | |
| 525 EXPECT_EQ(virtual_display_id_1, cached[1]->display_id()); | |
| 526 EXPECT_EQ(virtual_display_id_2, cached[2]->display_id()); | |
| 527 | |
| 528 // Remove 1st virtual display. | |
| 529 observer_.Reset(); | |
| 530 EXPECT_TRUE(configurator_.RemoveVirtualDisplay(virtual_display_id_1)); | |
| 531 EXPECT_EQ( | |
| 532 JoinActions( | |
| 533 kGrab, GetFramebufferAction( | |
| 534 gfx::Size(big_mode_.size().width(), kSingleVirtualHeight), | |
| 535 outputs_[0].get(), nullptr) | |
| 536 .c_str(), | |
| 537 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 538 kUngrab, nullptr), | |
| 539 log_->GetActionsAndClear()); | |
| 540 EXPECT_EQ(1, observer_.num_changes()); | |
| 541 ASSERT_EQ(static_cast<size_t>(2u), cached.size()); | |
| 542 EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | |
| 543 EXPECT_EQ(big_mode_.size(), cached[1]->current_mode()->size()); | |
| 544 EXPECT_EQ(virtual_display_id_2, cached[1]->display_id()); | |
| 545 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 546 configurator_.display_state()); | |
| 547 | |
| 548 // Remove 2nd virtual display. | |
| 549 observer_.Reset(); | |
| 550 EXPECT_TRUE(configurator_.RemoveVirtualDisplay(virtual_display_id_2)); | |
| 551 EXPECT_EQ( | |
| 552 JoinActions( | |
| 553 kGrab, | |
| 554 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 555 .c_str(), | |
| 556 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 557 kUngrab, nullptr), | |
| 558 log_->GetActionsAndClear()); | |
| 559 EXPECT_EQ(1, observer_.num_changes()); | |
| 560 ASSERT_EQ(static_cast<size_t>(1), cached.size()); | |
| 561 EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | |
| 562 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state()); | |
| 563 } | |
| 564 | |
| 565 TEST_F(DisplayConfiguratorTest, ConnectSecondOutput) { | |
| 566 InitWithSingleOutput(); | |
| 567 | |
| 568 // Connect a second output and check that the configurator enters | |
| 569 // extended mode. | |
| 570 observer_.Reset(); | |
| 571 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 572 UpdateOutputs(2, true); | |
| 573 const int kDualHeight = small_mode_.size().height() + | |
| 574 DisplayConfigurator::kVerticalGap + | |
| 575 big_mode_.size().height(); | |
| 576 EXPECT_EQ( | |
| 577 JoinActions( | |
| 578 kGrab, | |
| 579 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 580 outputs_[0].get(), outputs_[1].get()) | |
| 581 .c_str(), | |
| 582 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 583 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 584 gfx::Point(0, small_mode_.size().height() + | |
| 585 DisplayConfigurator::kVerticalGap)) | |
| 586 .c_str(), | |
| 587 kUngrab, nullptr), | |
| 588 log_->GetActionsAndClear()); | |
| 589 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 590 EXPECT_EQ(1, observer_.num_changes()); | |
| 591 | |
| 592 observer_.Reset(); | |
| 593 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 594 EXPECT_EQ( | |
| 595 JoinActions( | |
| 596 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 597 outputs_[1].get()) | |
| 598 .c_str(), | |
| 599 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 600 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 601 kUngrab, nullptr), | |
| 602 log_->GetActionsAndClear()); | |
| 603 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 604 EXPECT_EQ(1, observer_.num_changes()); | |
| 605 | |
| 606 // Disconnect the second output. | |
| 607 observer_.Reset(); | |
| 608 UpdateOutputs(1, true); | |
| 609 EXPECT_EQ( | |
| 610 JoinActions( | |
| 611 kGrab, | |
| 612 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 613 .c_str(), | |
| 614 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 615 kUngrab, nullptr), | |
| 616 log_->GetActionsAndClear()); | |
| 617 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 618 EXPECT_EQ(1, observer_.num_changes()); | |
| 619 | |
| 620 // Get rid of shared modes to force software mirroring. | |
| 621 outputs_[1] = display::FakeDisplaySnapshot::Builder() | |
| 622 .SetId(kDisplayIds[1]) | |
| 623 .SetNativeMode(big_mode_.Clone()) | |
| 624 .SetCurrentMode(big_mode_.Clone()) | |
| 625 .SetType(DISPLAY_CONNECTION_TYPE_HDMI) | |
| 626 .SetIsAspectPerservingScaling(true) | |
| 627 .Build(); | |
| 628 | |
| 629 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 630 UpdateOutputs(2, true); | |
| 631 EXPECT_EQ( | |
| 632 JoinActions( | |
| 633 kGrab, | |
| 634 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 635 outputs_[0].get(), outputs_[1].get()) | |
| 636 .c_str(), | |
| 637 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 638 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 639 gfx::Point(0, small_mode_.size().height() + | |
| 640 DisplayConfigurator::kVerticalGap)) | |
| 641 .c_str(), | |
| 642 kUngrab, nullptr), | |
| 643 log_->GetActionsAndClear()); | |
| 644 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 645 const gfx::Size framebuffer_size = configurator_.framebuffer_size(); | |
| 646 DCHECK(!framebuffer_size.IsEmpty()); | |
| 647 | |
| 648 observer_.Reset(); | |
| 649 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 650 EXPECT_EQ(JoinActions(kGrab, kUngrab, nullptr), log_->GetActionsAndClear()); | |
| 651 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 652 configurator_.display_state()); | |
| 653 EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 654 EXPECT_EQ(framebuffer_size.ToString(), | |
| 655 configurator_.framebuffer_size().ToString()); | |
| 656 | |
| 657 EXPECT_EQ(1, observer_.num_changes()); | |
| 658 | |
| 659 // Setting MULTIPLE_DISPLAY_STATE_DUAL_MIRROR should try to reconfigure. | |
| 660 observer_.Reset(); | |
| 661 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 662 EXPECT_EQ(JoinActions(nullptr), log_->GetActionsAndClear()); | |
| 663 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 664 EXPECT_EQ(1, observer_.num_changes()); | |
| 665 | |
| 666 // Set back to software mirror mode. | |
| 667 observer_.Reset(); | |
| 668 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 669 EXPECT_EQ(JoinActions(kGrab, kUngrab, nullptr), log_->GetActionsAndClear()); | |
| 670 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 671 configurator_.display_state()); | |
| 672 EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 673 EXPECT_EQ(1, observer_.num_changes()); | |
| 674 | |
| 675 // Disconnect the second output. | |
| 676 observer_.Reset(); | |
| 677 UpdateOutputs(1, true); | |
| 678 EXPECT_EQ( | |
| 679 JoinActions( | |
| 680 kGrab, | |
| 681 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 682 .c_str(), | |
| 683 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 684 kUngrab, nullptr), | |
| 685 log_->GetActionsAndClear()); | |
| 686 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 687 EXPECT_EQ(1, observer_.num_changes()); | |
| 688 } | |
| 689 | |
| 690 TEST_F(DisplayConfiguratorTest, SetDisplayPower) { | |
| 691 InitWithSingleOutput(); | |
| 692 | |
| 693 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 694 observer_.Reset(); | |
| 695 UpdateOutputs(2, true); | |
| 696 EXPECT_EQ( | |
| 697 JoinActions( | |
| 698 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 699 outputs_[1].get()) | |
| 700 .c_str(), | |
| 701 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 702 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 703 kUngrab, nullptr), | |
| 704 log_->GetActionsAndClear()); | |
| 705 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 706 EXPECT_EQ(1, observer_.num_changes()); | |
| 707 | |
| 708 // Turning off the internal display should switch the external display to | |
| 709 // its native mode. | |
| 710 observer_.Reset(); | |
| 711 config_waiter_.Reset(); | |
| 712 configurator_.SetDisplayPower( | |
| 713 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, | |
| 714 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 715 config_waiter_.on_configuration_callback()); | |
| 716 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 717 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 718 EXPECT_EQ( | |
| 719 JoinActions( | |
| 720 kGrab, GetFramebufferAction(big_mode_.size(), outputs_[0].get(), | |
| 721 outputs_[1].get()) | |
| 722 .c_str(), | |
| 723 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 724 GetCrtcAction(*outputs_[1], &big_mode_, gfx::Point(0, 0)).c_str(), | |
| 725 kForceDPMS, kUngrab, nullptr), | |
| 726 log_->GetActionsAndClear()); | |
| 727 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state()); | |
| 728 EXPECT_EQ(1, observer_.num_changes()); | |
| 729 | |
| 730 // When all displays are turned off, the framebuffer should switch back | |
| 731 // to the mirrored size. | |
| 732 observer_.Reset(); | |
| 733 config_waiter_.Reset(); | |
| 734 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 735 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 736 config_waiter_.on_configuration_callback()); | |
| 737 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 738 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 739 EXPECT_EQ( | |
| 740 JoinActions( | |
| 741 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 742 outputs_[1].get()) | |
| 743 .c_str(), | |
| 744 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 745 GetCrtcAction(*outputs_[1], nullptr, gfx::Point(0, 0)).c_str(), | |
| 746 kUngrab, nullptr), | |
| 747 log_->GetActionsAndClear()); | |
| 748 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state()); | |
| 749 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 750 EXPECT_EQ(1, observer_.num_changes()); | |
| 751 | |
| 752 // Turn all displays on and check that mirroring is still used. | |
| 753 observer_.Reset(); | |
| 754 config_waiter_.Reset(); | |
| 755 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 756 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 757 config_waiter_.on_configuration_callback()); | |
| 758 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 759 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 760 EXPECT_EQ( | |
| 761 JoinActions( | |
| 762 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 763 outputs_[1].get()) | |
| 764 .c_str(), | |
| 765 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 766 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 767 kForceDPMS, kUngrab, nullptr), | |
| 768 log_->GetActionsAndClear()); | |
| 769 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state()); | |
| 770 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 771 EXPECT_EQ(1, observer_.num_changes()); | |
| 772 | |
| 773 // Get rid of shared modes to force software mirroring. | |
| 774 outputs_[1] = display::FakeDisplaySnapshot::Builder() | |
| 775 .SetId(kDisplayIds[1]) | |
| 776 .SetNativeMode(big_mode_.Clone()) | |
| 777 .SetCurrentMode(big_mode_.Clone()) | |
| 778 .SetType(DISPLAY_CONNECTION_TYPE_HDMI) | |
| 779 .SetIsAspectPerservingScaling(true) | |
| 780 .Build(); | |
| 781 | |
| 782 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 783 observer_.Reset(); | |
| 784 UpdateOutputs(2, true); | |
| 785 const int kDualHeight = small_mode_.size().height() + | |
| 786 DisplayConfigurator::kVerticalGap + | |
| 787 big_mode_.size().height(); | |
| 788 EXPECT_EQ( | |
| 789 JoinActions( | |
| 790 kGrab, | |
| 791 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 792 outputs_[0].get(), outputs_[1].get()) | |
| 793 .c_str(), | |
| 794 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 795 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 796 gfx::Point(0, small_mode_.size().height() + | |
| 797 DisplayConfigurator::kVerticalGap)) | |
| 798 .c_str(), | |
| 799 kUngrab, nullptr), | |
| 800 log_->GetActionsAndClear()); | |
| 801 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 802 configurator_.display_state()); | |
| 803 EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 804 EXPECT_EQ(1, observer_.num_changes()); | |
| 805 | |
| 806 // Turning off the internal display should switch the external display to | |
| 807 // its native mode. | |
| 808 observer_.Reset(); | |
| 809 config_waiter_.Reset(); | |
| 810 configurator_.SetDisplayPower( | |
| 811 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, | |
| 812 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 813 config_waiter_.on_configuration_callback()); | |
| 814 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 815 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 816 EXPECT_EQ( | |
| 817 JoinActions( | |
| 818 kGrab, GetFramebufferAction(big_mode_.size(), outputs_[0].get(), | |
| 819 outputs_[1].get()) | |
| 820 .c_str(), | |
| 821 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 822 GetCrtcAction(*outputs_[1], &big_mode_, gfx::Point(0, 0)).c_str(), | |
| 823 kForceDPMS, kUngrab, nullptr), | |
| 824 log_->GetActionsAndClear()); | |
| 825 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state()); | |
| 826 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 827 EXPECT_EQ(1, observer_.num_changes()); | |
| 828 | |
| 829 // When all displays are turned off, the framebuffer should switch back | |
| 830 // to the extended + software mirroring. | |
| 831 observer_.Reset(); | |
| 832 config_waiter_.Reset(); | |
| 833 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 834 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 835 config_waiter_.on_configuration_callback()); | |
| 836 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 837 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 838 EXPECT_EQ( | |
| 839 JoinActions( | |
| 840 kGrab, | |
| 841 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 842 outputs_[0].get(), outputs_[1].get()) | |
| 843 .c_str(), | |
| 844 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 845 GetCrtcAction(*outputs_[1], nullptr, | |
| 846 gfx::Point(0, small_mode_.size().height() + | |
| 847 DisplayConfigurator::kVerticalGap)) | |
| 848 .c_str(), | |
| 849 kUngrab, nullptr), | |
| 850 log_->GetActionsAndClear()); | |
| 851 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 852 configurator_.display_state()); | |
| 853 EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 854 EXPECT_EQ(1, observer_.num_changes()); | |
| 855 | |
| 856 // Turn all displays on and check that mirroring is still used. | |
| 857 observer_.Reset(); | |
| 858 config_waiter_.Reset(); | |
| 859 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 860 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 861 config_waiter_.on_configuration_callback()); | |
| 862 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 863 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 864 EXPECT_EQ( | |
| 865 JoinActions( | |
| 866 kGrab, | |
| 867 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 868 outputs_[0].get(), outputs_[1].get()) | |
| 869 .c_str(), | |
| 870 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 871 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 872 gfx::Point(0, small_mode_.size().height() + | |
| 873 DisplayConfigurator::kVerticalGap)) | |
| 874 .c_str(), | |
| 875 kForceDPMS, kUngrab, nullptr), | |
| 876 log_->GetActionsAndClear()); | |
| 877 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 878 configurator_.display_state()); | |
| 879 EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 880 EXPECT_EQ(1, observer_.num_changes()); | |
| 881 } | |
| 882 | |
| 883 TEST_F(DisplayConfiguratorTest, SuspendAndResume) { | |
| 884 InitWithSingleOutput(); | |
| 885 | |
| 886 // No preparation is needed before suspending when the display is already | |
| 887 // on. The configurator should still reprobe on resume in case a display | |
| 888 // was connected while suspended. | |
| 889 const gfx::Size framebuffer_size = configurator_.framebuffer_size(); | |
| 890 DCHECK(!framebuffer_size.IsEmpty()); | |
| 891 config_waiter_.Reset(); | |
| 892 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 893 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 894 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 895 EXPECT_EQ(framebuffer_size.ToString(), | |
| 896 configurator_.framebuffer_size().ToString()); | |
| 897 EXPECT_EQ(JoinActions( | |
| 898 kGrab, GetFramebufferAction(small_mode_.size(), | |
| 899 outputs_[0].get(), nullptr) | |
| 900 .c_str(), | |
| 901 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 902 kUngrab, kSync, nullptr), | |
| 903 log_->GetActionsAndClear()); | |
| 904 | |
| 905 // No resume delay in single display mode. | |
| 906 config_waiter_.Reset(); | |
| 907 configurator_.ResumeDisplays(); | |
| 908 // The timer should not be running. | |
| 909 EXPECT_EQ(base::TimeDelta::Max(), config_waiter_.Wait()); | |
| 910 EXPECT_EQ( | |
| 911 JoinActions( | |
| 912 kGrab, | |
| 913 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 914 .c_str(), | |
| 915 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 916 kForceDPMS, kUngrab, nullptr), | |
| 917 log_->GetActionsAndClear()); | |
| 918 | |
| 919 // Now turn the display off before suspending and check that the | |
| 920 // configurator turns it back on and syncs with the server. | |
| 921 config_waiter_.Reset(); | |
| 922 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 923 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 924 config_waiter_.on_configuration_callback()); | |
| 925 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 926 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 927 EXPECT_EQ(JoinActions( | |
| 928 kGrab, GetFramebufferAction(small_mode_.size(), | |
| 929 outputs_[0].get(), nullptr) | |
| 930 .c_str(), | |
| 931 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 932 kUngrab, nullptr), | |
| 933 log_->GetActionsAndClear()); | |
| 934 | |
| 935 config_waiter_.Reset(); | |
| 936 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 937 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 938 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 939 EXPECT_EQ(kSync, log_->GetActionsAndClear()); | |
| 940 | |
| 941 config_waiter_.Reset(); | |
| 942 configurator_.ResumeDisplays(); | |
| 943 // The timer should not be running. | |
| 944 EXPECT_EQ(base::TimeDelta::Max(), config_waiter_.Wait()); | |
| 945 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 946 | |
| 947 config_waiter_.Reset(); | |
| 948 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 949 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 950 config_waiter_.on_configuration_callback()); | |
| 951 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 952 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 953 EXPECT_EQ( | |
| 954 JoinActions( | |
| 955 kGrab, | |
| 956 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 957 .c_str(), | |
| 958 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 959 kForceDPMS, kUngrab, nullptr), | |
| 960 log_->GetActionsAndClear()); | |
| 961 | |
| 962 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 963 UpdateOutputs(2, true); | |
| 964 EXPECT_EQ( | |
| 965 JoinActions( | |
| 966 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 967 outputs_[1].get()) | |
| 968 .c_str(), | |
| 969 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 970 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 971 kUngrab, nullptr), | |
| 972 log_->GetActionsAndClear()); | |
| 973 | |
| 974 config_waiter_.Reset(); | |
| 975 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 976 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 977 config_waiter_.on_configuration_callback()); | |
| 978 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 979 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 980 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state()); | |
| 981 EXPECT_EQ( | |
| 982 JoinActions( | |
| 983 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 984 outputs_[1].get()) | |
| 985 .c_str(), | |
| 986 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 987 GetCrtcAction(*outputs_[1], nullptr, gfx::Point(0, 0)).c_str(), | |
| 988 kUngrab, nullptr), | |
| 989 log_->GetActionsAndClear()); | |
| 990 | |
| 991 // No delay in suspend. | |
| 992 config_waiter_.Reset(); | |
| 993 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 994 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 995 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 996 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 997 configurator_.current_power_state()); | |
| 998 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state()); | |
| 999 EXPECT_EQ(kSync, log_->GetActionsAndClear()); | |
| 1000 | |
| 1001 // If a display is disconnected while suspended, the configurator should | |
| 1002 // pick up the change and only turn on the internal display. The should be | |
| 1003 // a longer configuration delay when we set the displays back to on. | |
| 1004 UpdateOutputs(1, false); | |
| 1005 config_waiter_.Reset(); | |
| 1006 configurator_.ResumeDisplays(); | |
| 1007 // Since we were in dual display mirror mode before suspend, the timer should | |
| 1008 // be running with kMinLongDelayMs. | |
| 1009 EXPECT_EQ(kLongDelay, test_api_.GetConfigureDelay()); | |
| 1010 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1011 | |
| 1012 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1013 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1014 config_waiter_.on_configuration_callback()); | |
| 1015 EXPECT_EQ(CALLBACK_NOT_CALLED, config_waiter_.callback_result()); | |
| 1016 EXPECT_EQ(kLongDelay, config_waiter_.Wait()); | |
| 1017 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1018 EXPECT_EQ( | |
| 1019 JoinActions( | |
| 1020 kGrab, | |
| 1021 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 1022 .c_str(), | |
| 1023 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1024 kForceDPMS, kUngrab, nullptr), | |
| 1025 log_->GetActionsAndClear()); | |
| 1026 } | |
| 1027 | |
| 1028 TEST_F(DisplayConfiguratorTest, Headless) { | |
| 1029 UpdateOutputs(0, false); | |
| 1030 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1031 Init(false); | |
| 1032 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1033 configurator_.ForceInitialConfigure(0); | |
| 1034 EXPECT_EQ(JoinActions(kInitXRandR, kGrab, kForceDPMS, kUngrab, nullptr), | |
| 1035 log_->GetActionsAndClear()); | |
| 1036 | |
| 1037 // Not much should happen when the display power state is changed while | |
| 1038 // no displays are connected. | |
| 1039 config_waiter_.Reset(); | |
| 1040 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 1041 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1042 config_waiter_.on_configuration_callback()); | |
| 1043 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1044 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1045 EXPECT_EQ(JoinActions(kGrab, kUngrab, nullptr), log_->GetActionsAndClear()); | |
| 1046 config_waiter_.Reset(); | |
| 1047 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1048 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1049 config_waiter_.on_configuration_callback()); | |
| 1050 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1051 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1052 EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, nullptr), | |
| 1053 log_->GetActionsAndClear()); | |
| 1054 | |
| 1055 // Connect an external display and check that it's configured correctly. | |
| 1056 outputs_[0] = display::FakeDisplaySnapshot::Builder() | |
| 1057 .SetId(kDisplayIds[0]) | |
| 1058 .SetNativeMode(big_mode_.Clone()) | |
| 1059 .SetCurrentMode(big_mode_.Clone()) | |
| 1060 .AddMode(small_mode_.Clone()) | |
| 1061 .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL) | |
| 1062 .SetIsAspectPerservingScaling(true) | |
| 1063 .Build(); | |
| 1064 | |
| 1065 UpdateOutputs(1, true); | |
| 1066 EXPECT_EQ( | |
| 1067 JoinActions( | |
| 1068 kGrab, | |
| 1069 GetFramebufferAction(big_mode_.size(), outputs_[0].get(), nullptr) | |
| 1070 .c_str(), | |
| 1071 GetCrtcAction(*outputs_[0], &big_mode_, gfx::Point(0, 0)).c_str(), | |
| 1072 kUngrab, nullptr), | |
| 1073 log_->GetActionsAndClear()); | |
| 1074 const gfx::Size framebuffer_size = configurator_.framebuffer_size(); | |
| 1075 DCHECK(!framebuffer_size.IsEmpty()); | |
| 1076 | |
| 1077 UpdateOutputs(0, true); | |
| 1078 EXPECT_EQ(JoinActions(kGrab, kUngrab, nullptr), log_->GetActionsAndClear()); | |
| 1079 EXPECT_EQ(framebuffer_size.ToString(), | |
| 1080 configurator_.framebuffer_size().ToString()); | |
| 1081 } | |
| 1082 | |
| 1083 TEST_F(DisplayConfiguratorTest, StartWithTwoOutputs) { | |
| 1084 UpdateOutputs(2, false); | |
| 1085 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1086 Init(false); | |
| 1087 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1088 | |
| 1089 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1090 configurator_.ForceInitialConfigure(0); | |
| 1091 EXPECT_EQ( | |
| 1092 JoinActions( | |
| 1093 kInitXRandR, kGrab, | |
| 1094 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 1095 outputs_[1].get()) | |
| 1096 .c_str(), | |
| 1097 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1098 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1099 kForceDPMS, kUngrab, nullptr), | |
| 1100 log_->GetActionsAndClear()); | |
| 1101 } | |
| 1102 | |
| 1103 TEST_F(DisplayConfiguratorTest, InvalidMultipleDisplayStates) { | |
| 1104 UpdateOutputs(0, false); | |
| 1105 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1106 Init(false); | |
| 1107 configurator_.ForceInitialConfigure(0); | |
| 1108 observer_.Reset(); | |
| 1109 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_HEADLESS); | |
| 1110 EXPECT_EQ(1, observer_.num_changes()); | |
| 1111 EXPECT_EQ(0, observer_.num_failures()); | |
| 1112 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_SINGLE); | |
| 1113 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1114 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 1115 EXPECT_EQ(1, observer_.num_changes()); | |
| 1116 EXPECT_EQ(3, observer_.num_failures()); | |
| 1117 | |
| 1118 UpdateOutputs(1, true); | |
| 1119 observer_.Reset(); | |
| 1120 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_HEADLESS); | |
| 1121 EXPECT_EQ(0, observer_.num_changes()); | |
| 1122 EXPECT_EQ(1, observer_.num_failures()); | |
| 1123 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_SINGLE); | |
| 1124 EXPECT_EQ(1, observer_.num_changes()); | |
| 1125 EXPECT_EQ(1, observer_.num_failures()); | |
| 1126 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1127 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 1128 EXPECT_EQ(1, observer_.num_changes()); | |
| 1129 EXPECT_EQ(3, observer_.num_failures()); | |
| 1130 | |
| 1131 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 1132 UpdateOutputs(2, true); | |
| 1133 observer_.Reset(); | |
| 1134 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_HEADLESS); | |
| 1135 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_SINGLE); | |
| 1136 EXPECT_EQ(0, observer_.num_changes()); | |
| 1137 EXPECT_EQ(2, observer_.num_failures()); | |
| 1138 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1139 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 1140 EXPECT_EQ(2, observer_.num_changes()); | |
| 1141 EXPECT_EQ(2, observer_.num_failures()); | |
| 1142 } | |
| 1143 | |
| 1144 TEST_F(DisplayConfiguratorTest, GetMultipleDisplayStateForMirroredDisplays) { | |
| 1145 UpdateOutputs(2, false); | |
| 1146 Init(false); | |
| 1147 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1148 configurator_.ForceInitialConfigure(0); | |
| 1149 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state()); | |
| 1150 } | |
| 1151 | |
| 1152 TEST_F(DisplayConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) { | |
| 1153 InitWithSingleOutput(); | |
| 1154 const DisplayConfigurator::DisplayStateList& cached = | |
| 1155 configurator_.cached_displays(); | |
| 1156 ASSERT_EQ(static_cast<size_t>(1), cached.size()); | |
| 1157 EXPECT_EQ(outputs_[0]->current_mode(), cached[0]->current_mode()); | |
| 1158 | |
| 1159 // After connecting a second output, check that it shows up in | |
| 1160 // |cached_displays_| even if an invalid state is requested. | |
| 1161 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_SINGLE); | |
| 1162 UpdateOutputs(2, true); | |
| 1163 ASSERT_EQ(static_cast<size_t>(2), cached.size()); | |
| 1164 EXPECT_EQ(outputs_[0]->current_mode(), cached[0]->current_mode()); | |
| 1165 EXPECT_EQ(outputs_[1]->current_mode(), cached[1]->current_mode()); | |
| 1166 } | |
| 1167 | |
| 1168 TEST_F(DisplayConfiguratorTest, PanelFitting) { | |
| 1169 // Configure the internal display to support only the big mode and the | |
| 1170 // external display to support only the small mode. | |
| 1171 outputs_[0] = display::FakeDisplaySnapshot::Builder() | |
| 1172 .SetId(kDisplayIds[0]) | |
| 1173 .SetNativeMode(big_mode_.Clone()) | |
| 1174 .SetCurrentMode(big_mode_.Clone()) | |
| 1175 .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL) | |
| 1176 .SetIsAspectPerservingScaling(true) | |
| 1177 .Build(); | |
| 1178 | |
| 1179 outputs_[1] = display::FakeDisplaySnapshot::Builder() | |
| 1180 .SetId(kDisplayIds[1]) | |
| 1181 .SetNativeMode(small_mode_.Clone()) | |
| 1182 .SetCurrentMode(small_mode_.Clone()) | |
| 1183 .SetType(DISPLAY_CONNECTION_TYPE_HDMI) | |
| 1184 .SetIsAspectPerservingScaling(true) | |
| 1185 .Build(); | |
| 1186 | |
| 1187 // The small mode should be added to the internal output when requesting | |
| 1188 // mirrored mode. | |
| 1189 UpdateOutputs(2, false); | |
| 1190 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1191 Init(true /* is_panel_fitting_enabled */); | |
| 1192 configurator_.ForceInitialConfigure(0); | |
| 1193 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state()); | |
| 1194 EXPECT_EQ( | |
| 1195 JoinActions( | |
| 1196 kInitXRandR, kGrab, | |
| 1197 GetAddOutputModeAction(*outputs_[0], &small_mode_).c_str(), | |
| 1198 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 1199 outputs_[1].get()) | |
| 1200 .c_str(), | |
| 1201 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1202 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1203 kForceDPMS, kUngrab, nullptr), | |
| 1204 log_->GetActionsAndClear()); | |
| 1205 | |
| 1206 // Both outputs should be using the small mode. | |
| 1207 ASSERT_EQ(1, observer_.num_changes()); | |
| 1208 ASSERT_EQ(static_cast<size_t>(2), observer_.latest_outputs().size()); | |
| 1209 EXPECT_EQ(small_mode_.size(), | |
| 1210 observer_.latest_outputs()[0]->current_mode()->size()); | |
| 1211 EXPECT_EQ(small_mode_.size(), | |
| 1212 observer_.latest_outputs()[1]->current_mode()->size()); | |
| 1213 | |
| 1214 // Also test that there are 2 modes (instead of the initial one) in the | |
| 1215 // snapshot that was passed to the observer (http://crbug.com/289159). | |
| 1216 DisplaySnapshot* state = observer_.latest_outputs()[0]; | |
| 1217 ASSERT_EQ(2UL, state->modes().size()); | |
| 1218 } | |
| 1219 | |
| 1220 TEST_F(DisplayConfiguratorTest, ContentProtection) { | |
| 1221 Init(false); | |
| 1222 configurator_.ForceInitialConfigure(0); | |
| 1223 EXPECT_NE(kNoActions, log_->GetActionsAndClear()); | |
| 1224 | |
| 1225 DisplayConfigurator::ContentProtectionClientId id = | |
| 1226 configurator_.RegisterContentProtectionClient(); | |
| 1227 EXPECT_NE(0u, id); | |
| 1228 | |
| 1229 // One output. | |
| 1230 UpdateOutputs(1, true); | |
| 1231 EXPECT_NE(kNoActions, log_->GetActionsAndClear()); | |
| 1232 configurator_.QueryContentProtectionStatus( | |
| 1233 id, outputs_[0]->display_id(), | |
| 1234 base::Bind(&DisplayConfiguratorTest::QueryContentProtectionCallback, | |
| 1235 base::Unretained(this))); | |
| 1236 EXPECT_EQ(1, query_content_protection_call_count_); | |
| 1237 EXPECT_TRUE(query_content_protection_response_.success); | |
| 1238 EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_INTERNAL), | |
| 1239 query_content_protection_response_.link_mask); | |
| 1240 EXPECT_EQ(static_cast<uint32_t>(CONTENT_PROTECTION_METHOD_NONE), | |
| 1241 query_content_protection_response_.protection_mask); | |
| 1242 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1243 | |
| 1244 // Two outputs. | |
| 1245 UpdateOutputs(2, true); | |
| 1246 EXPECT_NE(kNoActions, log_->GetActionsAndClear()); | |
| 1247 configurator_.QueryContentProtectionStatus( | |
| 1248 id, outputs_[1]->display_id(), | |
| 1249 base::Bind(&DisplayConfiguratorTest::QueryContentProtectionCallback, | |
| 1250 base::Unretained(this))); | |
| 1251 EXPECT_EQ(2, query_content_protection_call_count_); | |
| 1252 EXPECT_TRUE(query_content_protection_response_.success); | |
| 1253 EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI), | |
| 1254 query_content_protection_response_.link_mask); | |
| 1255 EXPECT_EQ(static_cast<uint32_t>(CONTENT_PROTECTION_METHOD_NONE), | |
| 1256 query_content_protection_response_.protection_mask); | |
| 1257 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1258 | |
| 1259 configurator_.EnableContentProtection( | |
| 1260 id, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_HDCP, | |
| 1261 base::Bind(&DisplayConfiguratorTest::EnableContentProtectionCallback, | |
| 1262 base::Unretained(this))); | |
| 1263 EXPECT_EQ(1, enable_content_protection_call_count_); | |
| 1264 EXPECT_TRUE(enable_content_protection_status_); | |
| 1265 EXPECT_EQ(GetSetHDCPStateAction(*outputs_[1], HDCP_STATE_DESIRED), | |
| 1266 log_->GetActionsAndClear()); | |
| 1267 | |
| 1268 // Enable protection. | |
| 1269 native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED); | |
| 1270 configurator_.QueryContentProtectionStatus( | |
| 1271 id, outputs_[1]->display_id(), | |
| 1272 base::Bind(&DisplayConfiguratorTest::QueryContentProtectionCallback, | |
| 1273 base::Unretained(this))); | |
| 1274 EXPECT_EQ(3, query_content_protection_call_count_); | |
| 1275 EXPECT_TRUE(query_content_protection_response_.success); | |
| 1276 EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI), | |
| 1277 query_content_protection_response_.link_mask); | |
| 1278 EXPECT_EQ(static_cast<uint32_t>(CONTENT_PROTECTION_METHOD_HDCP), | |
| 1279 query_content_protection_response_.protection_mask); | |
| 1280 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1281 | |
| 1282 // Protections should be disabled after unregister. | |
| 1283 configurator_.UnregisterContentProtectionClient(id); | |
| 1284 EXPECT_EQ(GetSetHDCPStateAction(*outputs_[1], HDCP_STATE_UNDESIRED), | |
| 1285 log_->GetActionsAndClear()); | |
| 1286 } | |
| 1287 | |
| 1288 TEST_F(DisplayConfiguratorTest, DoNotConfigureWithSuspendedDisplays) { | |
| 1289 InitWithSingleOutput(); | |
| 1290 | |
| 1291 // The DisplayConfigurator may occasionally receive OnConfigurationChanged() | |
| 1292 // after the displays have been suspended. This event should be ignored since | |
| 1293 // the DisplayConfigurator will force a probe and reconfiguration of displays | |
| 1294 // at resume time. | |
| 1295 config_waiter_.Reset(); | |
| 1296 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 1297 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1298 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1299 EXPECT_EQ(JoinActions( | |
| 1300 kGrab, GetFramebufferAction(small_mode_.size(), | |
| 1301 outputs_[0].get(), nullptr) | |
| 1302 .c_str(), | |
| 1303 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1304 kUngrab, kSync, nullptr), | |
| 1305 log_->GetActionsAndClear()); | |
| 1306 | |
| 1307 // The configuration timer should not be started when the displays | |
| 1308 // are suspended. | |
| 1309 configurator_.OnConfigurationChanged(); | |
| 1310 EXPECT_FALSE(test_api_.TriggerConfigureTimeout()); | |
| 1311 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1312 | |
| 1313 // Calls to SetDisplayPower should do nothing if the power state doesn't | |
| 1314 // change. | |
| 1315 config_waiter_.Reset(); | |
| 1316 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 1317 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1318 config_waiter_.on_configuration_callback()); | |
| 1319 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1320 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1321 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1322 config_waiter_.Reset(); | |
| 1323 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1324 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1325 config_waiter_.on_configuration_callback()); | |
| 1326 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1327 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1328 EXPECT_EQ( | |
| 1329 JoinActions( | |
| 1330 kGrab, | |
| 1331 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 1332 .c_str(), | |
| 1333 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1334 kForceDPMS, kUngrab, nullptr), | |
| 1335 log_->GetActionsAndClear()); | |
| 1336 | |
| 1337 UpdateOutputs(2, false); | |
| 1338 configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1339 EXPECT_EQ( | |
| 1340 JoinActions( | |
| 1341 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 1342 outputs_[1].get()) | |
| 1343 .c_str(), | |
| 1344 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1345 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1346 kUngrab, nullptr), | |
| 1347 log_->GetActionsAndClear()); | |
| 1348 | |
| 1349 // The DisplayConfigurator should do nothing at resume time if there is no | |
| 1350 // state change. | |
| 1351 config_waiter_.Reset(); | |
| 1352 UpdateOutputs(1, false); | |
| 1353 configurator_.ResumeDisplays(); | |
| 1354 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1355 | |
| 1356 // If a configuration task is pending when the displays are suspended, that | |
| 1357 // task should not run either and the timer should be stopped. The displays | |
| 1358 // should be turned off by suspend. | |
| 1359 configurator_.OnConfigurationChanged(); | |
| 1360 config_waiter_.Reset(); | |
| 1361 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 1362 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1363 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1364 EXPECT_EQ(JoinActions( | |
| 1365 kGrab, GetFramebufferAction(small_mode_.size(), | |
| 1366 outputs_[0].get(), nullptr) | |
| 1367 .c_str(), | |
| 1368 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1369 kUngrab, kSync, nullptr), | |
| 1370 log_->GetActionsAndClear()); | |
| 1371 EXPECT_FALSE(test_api_.TriggerConfigureTimeout()); | |
| 1372 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1373 | |
| 1374 config_waiter_.Reset(); | |
| 1375 configurator_.ResumeDisplays(); | |
| 1376 // The timer should not be running. | |
| 1377 EXPECT_EQ(base::TimeDelta::Max(), config_waiter_.Wait()); | |
| 1378 EXPECT_EQ( | |
| 1379 JoinActions( | |
| 1380 kGrab, | |
| 1381 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 1382 .c_str(), | |
| 1383 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1384 kForceDPMS, kUngrab, nullptr), | |
| 1385 log_->GetActionsAndClear()); | |
| 1386 } | |
| 1387 | |
| 1388 TEST_F(DisplayConfiguratorTest, ContentProtectionTwoClients) { | |
| 1389 DisplayConfigurator::ContentProtectionClientId client1 = | |
| 1390 configurator_.RegisterContentProtectionClient(); | |
| 1391 DisplayConfigurator::ContentProtectionClientId client2 = | |
| 1392 configurator_.RegisterContentProtectionClient(); | |
| 1393 EXPECT_NE(client1, client2); | |
| 1394 | |
| 1395 Init(false); | |
| 1396 configurator_.ForceInitialConfigure(0); | |
| 1397 UpdateOutputs(2, true); | |
| 1398 EXPECT_NE(kNoActions, log_->GetActionsAndClear()); | |
| 1399 | |
| 1400 // Clients never know state enableness for methods that they didn't request. | |
| 1401 configurator_.EnableContentProtection( | |
| 1402 client1, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_HDCP, | |
| 1403 base::Bind(&DisplayConfiguratorTest::EnableContentProtectionCallback, | |
| 1404 base::Unretained(this))); | |
| 1405 EXPECT_EQ(1, enable_content_protection_call_count_); | |
| 1406 EXPECT_TRUE(enable_content_protection_status_); | |
| 1407 EXPECT_EQ(GetSetHDCPStateAction(*outputs_[1], HDCP_STATE_DESIRED).c_str(), | |
| 1408 log_->GetActionsAndClear()); | |
| 1409 native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED); | |
| 1410 | |
| 1411 configurator_.QueryContentProtectionStatus( | |
| 1412 client1, outputs_[1]->display_id(), | |
| 1413 base::Bind(&DisplayConfiguratorTest::QueryContentProtectionCallback, | |
| 1414 base::Unretained(this))); | |
| 1415 EXPECT_EQ(1, query_content_protection_call_count_); | |
| 1416 EXPECT_TRUE(query_content_protection_response_.success); | |
| 1417 EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI), | |
| 1418 query_content_protection_response_.link_mask); | |
| 1419 EXPECT_EQ(CONTENT_PROTECTION_METHOD_HDCP, | |
| 1420 query_content_protection_response_.protection_mask); | |
| 1421 | |
| 1422 configurator_.QueryContentProtectionStatus( | |
| 1423 client2, outputs_[1]->display_id(), | |
| 1424 base::Bind(&DisplayConfiguratorTest::QueryContentProtectionCallback, | |
| 1425 base::Unretained(this))); | |
| 1426 EXPECT_EQ(2, query_content_protection_call_count_); | |
| 1427 EXPECT_TRUE(query_content_protection_response_.success); | |
| 1428 EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI), | |
| 1429 query_content_protection_response_.link_mask); | |
| 1430 EXPECT_EQ(CONTENT_PROTECTION_METHOD_NONE, | |
| 1431 query_content_protection_response_.protection_mask); | |
| 1432 | |
| 1433 // Protections will be disabled only if no more clients request them. | |
| 1434 configurator_.EnableContentProtection( | |
| 1435 client2, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_NONE, | |
| 1436 base::Bind(&DisplayConfiguratorTest::EnableContentProtectionCallback, | |
| 1437 base::Unretained(this))); | |
| 1438 EXPECT_EQ(2, enable_content_protection_call_count_); | |
| 1439 EXPECT_TRUE(enable_content_protection_status_); | |
| 1440 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1441 | |
| 1442 configurator_.EnableContentProtection( | |
| 1443 client1, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_NONE, | |
| 1444 base::Bind(&DisplayConfiguratorTest::EnableContentProtectionCallback, | |
| 1445 base::Unretained(this))); | |
| 1446 EXPECT_EQ(3, enable_content_protection_call_count_); | |
| 1447 EXPECT_TRUE(enable_content_protection_status_); | |
| 1448 EXPECT_EQ(GetSetHDCPStateAction(*outputs_[1], HDCP_STATE_UNDESIRED).c_str(), | |
| 1449 log_->GetActionsAndClear()); | |
| 1450 } | |
| 1451 | |
| 1452 TEST_F(DisplayConfiguratorTest, ContentProtectionTwoClientsEnable) { | |
| 1453 DisplayConfigurator::ContentProtectionClientId client1 = | |
| 1454 configurator_.RegisterContentProtectionClient(); | |
| 1455 DisplayConfigurator::ContentProtectionClientId client2 = | |
| 1456 configurator_.RegisterContentProtectionClient(); | |
| 1457 EXPECT_NE(client1, client2); | |
| 1458 | |
| 1459 Init(false); | |
| 1460 configurator_.ForceInitialConfigure(0); | |
| 1461 UpdateOutputs(2, true); | |
| 1462 log_->GetActionsAndClear(); | |
| 1463 | |
| 1464 // Only enable once if HDCP is enabling. | |
| 1465 configurator_.EnableContentProtection( | |
| 1466 client1, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_HDCP, | |
| 1467 base::Bind(&DisplayConfiguratorTest::EnableContentProtectionCallback, | |
| 1468 base::Unretained(this))); | |
| 1469 EXPECT_EQ(1, enable_content_protection_call_count_); | |
| 1470 EXPECT_TRUE(enable_content_protection_status_); | |
| 1471 native_display_delegate_->set_hdcp_state(HDCP_STATE_DESIRED); | |
| 1472 configurator_.EnableContentProtection( | |
| 1473 client2, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_HDCP, | |
| 1474 base::Bind(&DisplayConfiguratorTest::EnableContentProtectionCallback, | |
| 1475 base::Unretained(this))); | |
| 1476 EXPECT_EQ(2, enable_content_protection_call_count_); | |
| 1477 EXPECT_TRUE(enable_content_protection_status_); | |
| 1478 EXPECT_EQ(GetSetHDCPStateAction(*outputs_[1], HDCP_STATE_DESIRED).c_str(), | |
| 1479 log_->GetActionsAndClear()); | |
| 1480 native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED); | |
| 1481 | |
| 1482 // Don't enable again if HDCP is already active. | |
| 1483 configurator_.EnableContentProtection( | |
| 1484 client1, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_HDCP, | |
| 1485 base::Bind(&DisplayConfiguratorTest::EnableContentProtectionCallback, | |
| 1486 base::Unretained(this))); | |
| 1487 EXPECT_EQ(3, enable_content_protection_call_count_); | |
| 1488 EXPECT_TRUE(enable_content_protection_status_); | |
| 1489 configurator_.EnableContentProtection( | |
| 1490 client2, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_HDCP, | |
| 1491 base::Bind(&DisplayConfiguratorTest::EnableContentProtectionCallback, | |
| 1492 base::Unretained(this))); | |
| 1493 EXPECT_EQ(4, enable_content_protection_call_count_); | |
| 1494 EXPECT_TRUE(enable_content_protection_status_); | |
| 1495 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1496 } | |
| 1497 | |
| 1498 TEST_F(DisplayConfiguratorTest, HandleConfigureCrtcFailure) { | |
| 1499 InitWithSingleOutput(); | |
| 1500 | |
| 1501 std::vector<std::unique_ptr<const DisplayMode>> modes; | |
| 1502 // The first mode is the mode we are requesting DisplayConfigurator to choose. | |
| 1503 // The test will be setup so that this mode will fail and it will have to | |
| 1504 // choose the next best option. | |
| 1505 modes.push_back(MakeDisplayMode(2560, 1600, false, 60.0)); | |
| 1506 modes.push_back(MakeDisplayMode(1024, 768, false, 60.0)); | |
| 1507 modes.push_back(MakeDisplayMode(1280, 720, false, 60.0)); | |
| 1508 modes.push_back(MakeDisplayMode(1920, 1080, false, 60.0)); | |
| 1509 modes.push_back(MakeDisplayMode(1920, 1080, false, 40.0)); | |
| 1510 | |
| 1511 outputs_[0] = display::FakeDisplaySnapshot::Builder() | |
| 1512 .SetId(kDisplayIds[0]) | |
| 1513 .SetNativeMode(modes[0]->Clone()) | |
| 1514 .SetCurrentMode(modes[0]->Clone()) | |
| 1515 .AddMode(modes[1]->Clone()) | |
| 1516 .AddMode(modes[2]->Clone()) | |
| 1517 .AddMode(modes[3]->Clone()) | |
| 1518 .AddMode(modes[4]->Clone()) | |
| 1519 .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL) | |
| 1520 .SetIsAspectPerservingScaling(true) | |
| 1521 .Build(); | |
| 1522 | |
| 1523 // First test simply fails in MULTIPLE_DISPLAY_STATE_SINGLE mode. This is | |
| 1524 // probably unrealistic but we want to make sure any assumptions don't creep | |
| 1525 // in. | |
| 1526 native_display_delegate_->set_max_configurable_pixels( | |
| 1527 modes[2]->size().GetArea()); | |
| 1528 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_SINGLE); | |
| 1529 UpdateOutputs(1, true); | |
| 1530 | |
| 1531 EXPECT_EQ( | |
| 1532 JoinActions( | |
| 1533 kGrab, | |
| 1534 GetFramebufferAction(big_mode_.size(), outputs_[0].get(), nullptr) | |
| 1535 .c_str(), | |
| 1536 GetCrtcAction(*outputs_[0], modes[0].get(), gfx::Point(0, 0)).c_str(), | |
| 1537 GetCrtcAction(*outputs_[0], modes[3].get(), gfx::Point(0, 0)).c_str(), | |
| 1538 GetCrtcAction(*outputs_[0], modes[2].get(), gfx::Point(0, 0)).c_str(), | |
| 1539 kUngrab, nullptr), | |
| 1540 log_->GetActionsAndClear()); | |
| 1541 | |
| 1542 outputs_[1] = display::FakeDisplaySnapshot::Builder() | |
| 1543 .SetId(kDisplayIds[1]) | |
| 1544 .SetNativeMode(modes[0]->Clone()) | |
| 1545 .SetCurrentMode(modes[0]->Clone()) | |
| 1546 .AddMode(modes[1]->Clone()) | |
| 1547 .AddMode(modes[2]->Clone()) | |
| 1548 .AddMode(modes[3]->Clone()) | |
| 1549 .AddMode(modes[4]->Clone()) | |
| 1550 .SetType(DISPLAY_CONNECTION_TYPE_HDMI) | |
| 1551 .SetIsAspectPerservingScaling(true) | |
| 1552 .Build(); | |
| 1553 | |
| 1554 // This test should attempt to configure a mirror mode that will not succeed | |
| 1555 // and should end up in extended mode. | |
| 1556 native_display_delegate_->set_max_configurable_pixels( | |
| 1557 modes[3]->size().GetArea()); | |
| 1558 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1559 UpdateOutputs(2, true); | |
| 1560 | |
| 1561 EXPECT_EQ( | |
| 1562 JoinActions( | |
| 1563 kGrab, GetFramebufferAction(modes[0]->size(), outputs_[0].get(), | |
| 1564 outputs_[1].get()) | |
| 1565 .c_str(), | |
| 1566 GetCrtcAction(*outputs_[0], modes[0].get(), gfx::Point(0, 0)).c_str(), | |
| 1567 // Then attempt to configure crtc1 with the first mode. | |
| 1568 GetCrtcAction(*outputs_[1], modes[0].get(), gfx::Point(0, 0)).c_str(), | |
| 1569 // First mode tried is expected to fail and it will | |
| 1570 // retry wil the 4th mode in the list. | |
| 1571 GetCrtcAction(*outputs_[0], modes[3].get(), gfx::Point(0, 0)).c_str(), | |
| 1572 GetCrtcAction(*outputs_[1], modes[3].get(), gfx::Point(0, 0)).c_str(), | |
| 1573 // Since it was requested to go into mirror mode | |
| 1574 // and the configured modes were different, it | |
| 1575 // should now try and setup a valid configurable | |
| 1576 // extended mode. | |
| 1577 GetFramebufferAction( | |
| 1578 gfx::Size(modes[0]->size().width(), | |
| 1579 modes[0]->size().height() + modes[0]->size().height() + | |
| 1580 DisplayConfigurator::kVerticalGap), | |
| 1581 outputs_[0].get(), outputs_[1].get()) | |
| 1582 .c_str(), | |
| 1583 GetCrtcAction(*outputs_[0], modes[0].get(), gfx::Point(0, 0)).c_str(), | |
| 1584 GetCrtcAction(*outputs_[1], modes[0].get(), | |
| 1585 gfx::Point(0, modes[0]->size().height() + | |
| 1586 DisplayConfigurator::kVerticalGap)) | |
| 1587 .c_str(), | |
| 1588 GetCrtcAction(*outputs_[0], modes[3].get(), gfx::Point(0, 0)).c_str(), | |
| 1589 GetCrtcAction(*outputs_[1], modes[3].get(), | |
| 1590 gfx::Point(0, modes[0]->size().height() + | |
| 1591 DisplayConfigurator::kVerticalGap)) | |
| 1592 .c_str(), | |
| 1593 kUngrab, nullptr), | |
| 1594 log_->GetActionsAndClear()); | |
| 1595 } | |
| 1596 | |
| 1597 // Tests that power state requests are saved after failed configuration attempts | |
| 1598 // so they can be reused later: http://crosbug.com/p/31571 | |
| 1599 TEST_F(DisplayConfiguratorTest, SaveDisplayPowerStateOnConfigFailure) { | |
| 1600 // Start out with two displays in extended mode. | |
| 1601 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 1602 Init(false); | |
| 1603 configurator_.ForceInitialConfigure(0); | |
| 1604 log_->GetActionsAndClear(); | |
| 1605 observer_.Reset(); | |
| 1606 | |
| 1607 // Turn off the internal display, simulating docked mode. | |
| 1608 config_waiter_.Reset(); | |
| 1609 configurator_.SetDisplayPower( | |
| 1610 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, | |
| 1611 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1612 config_waiter_.on_configuration_callback()); | |
| 1613 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1614 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1615 EXPECT_EQ(1, observer_.num_changes()); | |
| 1616 EXPECT_EQ(0, observer_.num_failures()); | |
| 1617 log_->GetActionsAndClear(); | |
| 1618 | |
| 1619 // Make all subsequent configuration requests fail and try to turn the | |
| 1620 // internal display back on. | |
| 1621 config_waiter_.Reset(); | |
| 1622 native_display_delegate_->set_max_configurable_pixels(1); | |
| 1623 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1624 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1625 config_waiter_.on_configuration_callback()); | |
| 1626 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1627 EXPECT_EQ(CALLBACK_FAILURE, config_waiter_.callback_result()); | |
| 1628 EXPECT_EQ(1, observer_.num_changes()); | |
| 1629 EXPECT_EQ(1, observer_.num_failures()); | |
| 1630 log_->GetActionsAndClear(); | |
| 1631 | |
| 1632 // Simulate the external display getting disconnected and check that the | |
| 1633 // internal display is turned on (i.e. DISPLAY_POWER_ALL_ON is used) rather | |
| 1634 // than the earlier DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON state. | |
| 1635 native_display_delegate_->set_max_configurable_pixels(0); | |
| 1636 UpdateOutputs(1, true); | |
| 1637 EXPECT_EQ( | |
| 1638 JoinActions( | |
| 1639 kGrab, | |
| 1640 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 1641 .c_str(), | |
| 1642 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1643 kForceDPMS, kUngrab, nullptr), | |
| 1644 log_->GetActionsAndClear()); | |
| 1645 } | |
| 1646 | |
| 1647 // Tests that the SetDisplayPowerState() task posted by HandleResume() doesn't | |
| 1648 // use a stale state if a new state is requested before it runs: | |
| 1649 // http://crosbug.com/p/32393 | |
| 1650 TEST_F(DisplayConfiguratorTest, DontRestoreStalePowerStateAfterResume) { | |
| 1651 // Start out with two displays in mirrored mode. | |
| 1652 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR); | |
| 1653 Init(false); | |
| 1654 configurator_.ForceInitialConfigure(0); | |
| 1655 log_->GetActionsAndClear(); | |
| 1656 observer_.Reset(); | |
| 1657 | |
| 1658 // Turn off the internal display, simulating docked mode. | |
| 1659 configurator_.SetDisplayPower( | |
| 1660 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, | |
| 1661 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1662 config_waiter_.on_configuration_callback()); | |
| 1663 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1664 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1665 EXPECT_EQ(1, observer_.num_changes()); | |
| 1666 EXPECT_EQ(0, observer_.num_failures()); | |
| 1667 EXPECT_EQ( | |
| 1668 JoinActions( | |
| 1669 kGrab, GetFramebufferAction(big_mode_.size(), outputs_[0].get(), | |
| 1670 outputs_[1].get()) | |
| 1671 .c_str(), | |
| 1672 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1673 GetCrtcAction(*outputs_[1], &big_mode_, gfx::Point(0, 0)).c_str(), | |
| 1674 kForceDPMS, kUngrab, nullptr), | |
| 1675 log_->GetActionsAndClear()); | |
| 1676 | |
| 1677 // Suspend and resume the system. Resuming should restore the previous power | |
| 1678 // state and force a probe. Suspend should turn off the displays since an | |
| 1679 // external monitor is connected. | |
| 1680 config_waiter_.Reset(); | |
| 1681 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 1682 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1683 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1684 EXPECT_EQ(2, observer_.num_changes()); | |
| 1685 EXPECT_EQ( | |
| 1686 JoinActions( | |
| 1687 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 1688 outputs_[1].get()) | |
| 1689 .c_str(), | |
| 1690 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1691 GetCrtcAction(*outputs_[1], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1692 kUngrab, kSync, nullptr), | |
| 1693 log_->GetActionsAndClear()); | |
| 1694 | |
| 1695 // Before the task runs, exit docked mode. | |
| 1696 config_waiter_.Reset(); | |
| 1697 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1698 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1699 config_waiter_.on_configuration_callback()); | |
| 1700 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1701 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1702 EXPECT_EQ(3, observer_.num_changes()); | |
| 1703 EXPECT_EQ(0, observer_.num_failures()); | |
| 1704 EXPECT_EQ( | |
| 1705 JoinActions( | |
| 1706 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 1707 outputs_[1].get()) | |
| 1708 .c_str(), | |
| 1709 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1710 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1711 kForceDPMS, kUngrab, nullptr), | |
| 1712 log_->GetActionsAndClear()); | |
| 1713 | |
| 1714 // Check that the display states are not changed after resuming. | |
| 1715 config_waiter_.Reset(); | |
| 1716 // Since we are in dual display mode, a configuration task is scheduled after | |
| 1717 // kMinLongDelayMs delay. | |
| 1718 configurator_.ResumeDisplays(); | |
| 1719 EXPECT_EQ(kLongDelay, test_api_.GetConfigureDelay()); | |
| 1720 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1721 configurator_.current_power_state()); | |
| 1722 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 1723 // Now trigger that delayed configuration. | |
| 1724 EXPECT_EQ(kLongDelay, config_waiter_.Wait()); | |
| 1725 EXPECT_EQ( | |
| 1726 JoinActions( | |
| 1727 kGrab, GetFramebufferAction(small_mode_.size(), outputs_[0].get(), | |
| 1728 outputs_[1].get()) | |
| 1729 .c_str(), | |
| 1730 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1731 GetCrtcAction(*outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1732 kUngrab, nullptr), | |
| 1733 log_->GetActionsAndClear()); | |
| 1734 } | |
| 1735 | |
| 1736 TEST_F(DisplayConfiguratorTest, ExternalControl) { | |
| 1737 InitWithSingleOutput(); | |
| 1738 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_SINGLE); | |
| 1739 configurator_.RelinquishControl( | |
| 1740 base::Bind(&DisplayConfiguratorTest::OnDisplayControlUpdated, | |
| 1741 base::Unretained(this))); | |
| 1742 EXPECT_EQ(CALLBACK_SUCCESS, PopDisplayControlResult()); | |
| 1743 EXPECT_EQ( | |
| 1744 JoinActions( | |
| 1745 kGrab, | |
| 1746 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 1747 .c_str(), | |
| 1748 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1749 kUngrab, kRelinquishDisplayControl, nullptr), | |
| 1750 log_->GetActionsAndClear()); | |
| 1751 configurator_.TakeControl( | |
| 1752 base::Bind(&DisplayConfiguratorTest::OnDisplayControlUpdated, | |
| 1753 base::Unretained(this))); | |
| 1754 EXPECT_EQ(CALLBACK_SUCCESS, PopDisplayControlResult()); | |
| 1755 EXPECT_EQ( | |
| 1756 JoinActions( | |
| 1757 kTakeDisplayControl, kGrab, | |
| 1758 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 1759 .c_str(), | |
| 1760 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1761 kForceDPMS, kUngrab, nullptr), | |
| 1762 log_->GetActionsAndClear()); | |
| 1763 } | |
| 1764 | |
| 1765 TEST_F(DisplayConfiguratorTest, | |
| 1766 SetDisplayPowerWhilePendingConfigurationTaskRunning) { | |
| 1767 // Start out with two displays in extended mode. | |
| 1768 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 1769 Init(false); | |
| 1770 configurator_.ForceInitialConfigure(0); | |
| 1771 log_->GetActionsAndClear(); | |
| 1772 observer_.Reset(); | |
| 1773 | |
| 1774 native_display_delegate_->set_run_async(true); | |
| 1775 | |
| 1776 config_waiter_.Reset(); | |
| 1777 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 1778 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1779 config_waiter_.on_configuration_callback()); | |
| 1780 EXPECT_EQ(CALLBACK_NOT_CALLED, config_waiter_.callback_result()); | |
| 1781 | |
| 1782 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1783 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1784 config_waiter_.on_configuration_callback()); | |
| 1785 | |
| 1786 EXPECT_EQ(CALLBACK_NOT_CALLED, config_waiter_.callback_result()); | |
| 1787 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1788 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1789 EXPECT_EQ(1, observer_.num_changes()); | |
| 1790 EXPECT_EQ(0, observer_.num_failures()); | |
| 1791 | |
| 1792 const int kDualHeight = small_mode_.size().height() + | |
| 1793 DisplayConfigurator::kVerticalGap + | |
| 1794 big_mode_.size().height(); | |
| 1795 EXPECT_EQ( | |
| 1796 JoinActions( | |
| 1797 kGrab, | |
| 1798 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 1799 outputs_[0].get(), outputs_[1].get()) | |
| 1800 .c_str(), | |
| 1801 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1802 GetCrtcAction(*outputs_[1], nullptr, | |
| 1803 gfx::Point(0, small_mode_.size().height() + | |
| 1804 DisplayConfigurator::kVerticalGap)) | |
| 1805 .c_str(), | |
| 1806 kUngrab, nullptr), | |
| 1807 log_->GetActionsAndClear()); | |
| 1808 | |
| 1809 config_waiter_.Reset(); | |
| 1810 EXPECT_EQ( | |
| 1811 base::TimeDelta::FromMilliseconds(DisplayConfigurator::kConfigureDelayMs), | |
| 1812 config_waiter_.Wait()); | |
| 1813 EXPECT_EQ(CALLBACK_NOT_CALLED, config_waiter_.callback_result()); | |
| 1814 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1815 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1816 EXPECT_EQ(2, observer_.num_changes()); | |
| 1817 EXPECT_EQ(0, observer_.num_failures()); | |
| 1818 | |
| 1819 EXPECT_EQ( | |
| 1820 JoinActions( | |
| 1821 kGrab, | |
| 1822 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 1823 outputs_[0].get(), outputs_[1].get()) | |
| 1824 .c_str(), | |
| 1825 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1826 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 1827 gfx::Point(0, small_mode_.size().height() + | |
| 1828 DisplayConfigurator::kVerticalGap)) | |
| 1829 .c_str(), | |
| 1830 kForceDPMS, kUngrab, nullptr), | |
| 1831 log_->GetActionsAndClear()); | |
| 1832 } | |
| 1833 | |
| 1834 TEST_F(DisplayConfiguratorTest, | |
| 1835 SetDisplayPowerAfterFailedDisplayConfiguration) { | |
| 1836 // Start out with two displays in extended mode. | |
| 1837 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 1838 Init(false); | |
| 1839 configurator_.ForceInitialConfigure(0); | |
| 1840 log_->GetActionsAndClear(); | |
| 1841 observer_.Reset(); | |
| 1842 | |
| 1843 // Fail display configuration. | |
| 1844 native_display_delegate_->set_max_configurable_pixels(-1); | |
| 1845 | |
| 1846 config_waiter_.Reset(); | |
| 1847 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 1848 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1849 config_waiter_.on_configuration_callback()); | |
| 1850 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1851 EXPECT_EQ(CALLBACK_FAILURE, config_waiter_.callback_result()); | |
| 1852 EXPECT_EQ(0, observer_.num_changes()); | |
| 1853 EXPECT_EQ(1, observer_.num_failures()); | |
| 1854 | |
| 1855 const int kDualHeight = small_mode_.size().height() + | |
| 1856 DisplayConfigurator::kVerticalGap + | |
| 1857 big_mode_.size().height(); | |
| 1858 | |
| 1859 EXPECT_EQ( | |
| 1860 JoinActions( | |
| 1861 kGrab, | |
| 1862 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 1863 outputs_[0].get(), outputs_[1].get()) | |
| 1864 .c_str(), | |
| 1865 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1866 GetCrtcAction(*outputs_[1], nullptr, | |
| 1867 gfx::Point(0, small_mode_.size().height() + | |
| 1868 DisplayConfigurator::kVerticalGap)) | |
| 1869 .c_str(), | |
| 1870 kUngrab, nullptr), | |
| 1871 log_->GetActionsAndClear()); | |
| 1872 | |
| 1873 // This configuration should trigger a display configuration since the | |
| 1874 // previous configuration failed. | |
| 1875 config_waiter_.Reset(); | |
| 1876 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1877 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1878 config_waiter_.on_configuration_callback()); | |
| 1879 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1880 | |
| 1881 EXPECT_EQ(0, observer_.num_changes()); | |
| 1882 EXPECT_EQ(2, observer_.num_failures()); | |
| 1883 EXPECT_EQ( | |
| 1884 JoinActions( | |
| 1885 kGrab, | |
| 1886 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 1887 outputs_[0].get(), outputs_[1].get()) | |
| 1888 .c_str(), | |
| 1889 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1890 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 1891 gfx::Point(0, small_mode_.size().height() + | |
| 1892 DisplayConfigurator::kVerticalGap)) | |
| 1893 .c_str(), | |
| 1894 GetCrtcAction(*outputs_[1], &small_mode_, | |
| 1895 gfx::Point(0, small_mode_.size().height() + | |
| 1896 DisplayConfigurator::kVerticalGap)) | |
| 1897 .c_str(), | |
| 1898 kUngrab, nullptr), | |
| 1899 log_->GetActionsAndClear()); | |
| 1900 | |
| 1901 // Allow configuration to succeed. | |
| 1902 native_display_delegate_->set_max_configurable_pixels(0); | |
| 1903 | |
| 1904 // Validate that a configuration event has the proper power state (displays | |
| 1905 // should be on). | |
| 1906 configurator_.OnConfigurationChanged(); | |
| 1907 EXPECT_TRUE(test_api_.TriggerConfigureTimeout()); | |
| 1908 | |
| 1909 EXPECT_EQ(1, observer_.num_changes()); | |
| 1910 EXPECT_EQ(2, observer_.num_failures()); | |
| 1911 | |
| 1912 EXPECT_EQ( | |
| 1913 JoinActions( | |
| 1914 kGrab, | |
| 1915 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 1916 outputs_[0].get(), outputs_[1].get()) | |
| 1917 .c_str(), | |
| 1918 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1919 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 1920 gfx::Point(0, small_mode_.size().height() + | |
| 1921 DisplayConfigurator::kVerticalGap)) | |
| 1922 .c_str(), | |
| 1923 kUngrab, nullptr), | |
| 1924 log_->GetActionsAndClear()); | |
| 1925 } | |
| 1926 | |
| 1927 TEST_F(DisplayConfiguratorTest, TestWithThreeDisplays) { | |
| 1928 // Start out with two displays in extended mode. | |
| 1929 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 1930 Init(false); | |
| 1931 configurator_.ForceInitialConfigure(0); | |
| 1932 log_->GetActionsAndClear(); | |
| 1933 observer_.Reset(); | |
| 1934 | |
| 1935 UpdateOutputs(3, true); | |
| 1936 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED); | |
| 1937 | |
| 1938 const int kDualHeight = small_mode_.size().height() + | |
| 1939 DisplayConfigurator::kVerticalGap + | |
| 1940 big_mode_.size().height(); | |
| 1941 const int kTripleHeight = 2 * small_mode_.size().height() + | |
| 1942 2 * DisplayConfigurator::kVerticalGap + | |
| 1943 big_mode_.size().height(); | |
| 1944 EXPECT_EQ( | |
| 1945 JoinActions( | |
| 1946 kGrab, GetFramebufferAction( | |
| 1947 gfx::Size(big_mode_.size().width(), kTripleHeight), | |
| 1948 outputs_[0].get(), outputs_[1].get()) | |
| 1949 .c_str(), | |
| 1950 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 1951 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 1952 gfx::Point(0, small_mode_.size().height() + | |
| 1953 DisplayConfigurator::kVerticalGap)) | |
| 1954 .c_str(), | |
| 1955 GetCrtcAction( | |
| 1956 *outputs_[2], &small_mode_, | |
| 1957 gfx::Point(0, small_mode_.size().height() + | |
| 1958 big_mode_.size().height() + | |
| 1959 2 * DisplayConfigurator::kVerticalGap)) | |
| 1960 .c_str(), | |
| 1961 kUngrab, nullptr), | |
| 1962 log_->GetActionsAndClear()); | |
| 1963 | |
| 1964 // Verify that turning the power off works. | |
| 1965 config_waiter_.Reset(); | |
| 1966 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 1967 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1968 config_waiter_.on_configuration_callback()); | |
| 1969 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1970 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1971 EXPECT_EQ( | |
| 1972 JoinActions( | |
| 1973 kGrab, GetFramebufferAction( | |
| 1974 gfx::Size(big_mode_.size().width(), kTripleHeight), | |
| 1975 outputs_[0].get(), outputs_[1].get()) | |
| 1976 .c_str(), | |
| 1977 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 1978 GetCrtcAction(*outputs_[1], nullptr, | |
| 1979 gfx::Point(0, small_mode_.size().height() + | |
| 1980 DisplayConfigurator::kVerticalGap)) | |
| 1981 .c_str(), | |
| 1982 GetCrtcAction( | |
| 1983 *outputs_[2], nullptr, | |
| 1984 gfx::Point(0, small_mode_.size().height() + | |
| 1985 big_mode_.size().height() + | |
| 1986 2 * DisplayConfigurator::kVerticalGap)) | |
| 1987 .c_str(), | |
| 1988 kUngrab, nullptr), | |
| 1989 log_->GetActionsAndClear()); | |
| 1990 | |
| 1991 config_waiter_.Reset(); | |
| 1992 configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, | |
| 1993 DisplayConfigurator::kSetDisplayPowerNoFlags, | |
| 1994 config_waiter_.on_configuration_callback()); | |
| 1995 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 1996 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 1997 EXPECT_EQ( | |
| 1998 JoinActions( | |
| 1999 kGrab, GetFramebufferAction( | |
| 2000 gfx::Size(big_mode_.size().width(), kTripleHeight), | |
| 2001 outputs_[0].get(), outputs_[1].get()) | |
| 2002 .c_str(), | |
| 2003 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 2004 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 2005 gfx::Point(0, small_mode_.size().height() + | |
| 2006 DisplayConfigurator::kVerticalGap)) | |
| 2007 .c_str(), | |
| 2008 GetCrtcAction( | |
| 2009 *outputs_[2], &small_mode_, | |
| 2010 gfx::Point(0, small_mode_.size().height() + | |
| 2011 big_mode_.size().height() + | |
| 2012 2 * DisplayConfigurator::kVerticalGap)) | |
| 2013 .c_str(), | |
| 2014 kForceDPMS, kUngrab, nullptr), | |
| 2015 log_->GetActionsAndClear()); | |
| 2016 | |
| 2017 // Disconnect the third output. | |
| 2018 observer_.Reset(); | |
| 2019 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 2020 UpdateOutputs(2, true); | |
| 2021 EXPECT_EQ( | |
| 2022 JoinActions( | |
| 2023 kGrab, | |
| 2024 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 2025 outputs_[0].get(), outputs_[1].get()) | |
| 2026 .c_str(), | |
| 2027 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 2028 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 2029 gfx::Point(0, small_mode_.size().height() + | |
| 2030 DisplayConfigurator::kVerticalGap)) | |
| 2031 .c_str(), | |
| 2032 kUngrab, nullptr), | |
| 2033 log_->GetActionsAndClear()); | |
| 2034 } | |
| 2035 | |
| 2036 // Tests the suspend and resume behavior when in dual or multi display modes. | |
| 2037 TEST_F(DisplayConfiguratorTest, SuspendResumeWithMultipleDisplays) { | |
| 2038 InitWithSingleOutput(); | |
| 2039 state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED); | |
| 2040 observer_.Reset(); | |
| 2041 UpdateOutputs(2, true); | |
| 2042 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 2043 configurator_.display_state()); | |
| 2044 EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | |
| 2045 EXPECT_EQ(1, observer_.num_changes()); | |
| 2046 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON, | |
| 2047 configurator_.current_power_state()); | |
| 2048 const int kDualHeight = small_mode_.size().height() + | |
| 2049 DisplayConfigurator::kVerticalGap + | |
| 2050 big_mode_.size().height(); | |
| 2051 EXPECT_EQ( | |
| 2052 JoinActions( | |
| 2053 kGrab, | |
| 2054 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 2055 outputs_[0].get(), outputs_[1].get()) | |
| 2056 .c_str(), | |
| 2057 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 2058 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 2059 gfx::Point(0, small_mode_.size().height() + | |
| 2060 DisplayConfigurator::kVerticalGap)) | |
| 2061 .c_str(), | |
| 2062 kUngrab, nullptr), | |
| 2063 log_->GetActionsAndClear()); | |
| 2064 | |
| 2065 // Suspending displays should result in an immediate configuration without | |
| 2066 // delays, even in dual display mode. | |
| 2067 config_waiter_.Reset(); | |
| 2068 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 2069 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 2070 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 2071 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 2072 configurator_.current_power_state()); | |
| 2073 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 2074 configurator_.display_state()); | |
| 2075 EXPECT_EQ( | |
| 2076 JoinActions( | |
| 2077 kGrab, | |
| 2078 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 2079 outputs_[0].get(), outputs_[1].get()) | |
| 2080 .c_str(), | |
| 2081 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 2082 GetCrtcAction(*outputs_[1], nullptr, | |
| 2083 gfx::Point(0, small_mode_.size().height() + | |
| 2084 DisplayConfigurator::kVerticalGap)) | |
| 2085 .c_str(), | |
| 2086 kUngrab, kSync, nullptr), | |
| 2087 log_->GetActionsAndClear()); | |
| 2088 | |
| 2089 // Resuming from suspend with dual displays. Configuration should be done | |
| 2090 // after a long delay. Afterwards, we should still expect to be in a dual | |
| 2091 // display mode. | |
| 2092 config_waiter_.Reset(); | |
| 2093 configurator_.ResumeDisplays(); | |
| 2094 EXPECT_EQ(kLongDelay, config_waiter_.Wait()); | |
| 2095 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON, | |
| 2096 configurator_.current_power_state()); | |
| 2097 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 2098 configurator_.display_state()); | |
| 2099 EXPECT_EQ( | |
| 2100 JoinActions( | |
| 2101 kGrab, | |
| 2102 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 2103 outputs_[0].get(), outputs_[1].get()) | |
| 2104 .c_str(), | |
| 2105 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 2106 GetCrtcAction(*outputs_[1], &big_mode_, | |
| 2107 gfx::Point(0, small_mode_.size().height() + | |
| 2108 DisplayConfigurator::kVerticalGap)) | |
| 2109 .c_str(), | |
| 2110 kForceDPMS, kUngrab, nullptr), | |
| 2111 log_->GetActionsAndClear()); | |
| 2112 | |
| 2113 // Suspend displays and disconnect one of them while in suspend. | |
| 2114 config_waiter_.Reset(); | |
| 2115 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 2116 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 2117 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 2118 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | |
| 2119 configurator_.display_state()); | |
| 2120 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 2121 configurator_.current_power_state()); | |
| 2122 EXPECT_EQ( | |
| 2123 JoinActions( | |
| 2124 kGrab, | |
| 2125 GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight), | |
| 2126 outputs_[0].get(), outputs_[1].get()) | |
| 2127 .c_str(), | |
| 2128 GetCrtcAction(*outputs_[0], nullptr, gfx::Point(0, 0)).c_str(), | |
| 2129 GetCrtcAction(*outputs_[1], nullptr, | |
| 2130 gfx::Point(0, small_mode_.size().height() + | |
| 2131 DisplayConfigurator::kVerticalGap)) | |
| 2132 .c_str(), | |
| 2133 kUngrab, kSync, nullptr), | |
| 2134 log_->GetActionsAndClear()); | |
| 2135 UpdateOutputs(1, false); | |
| 2136 EXPECT_EQ(kNoActions, log_->GetActionsAndClear()); | |
| 2137 | |
| 2138 // Now resume, and expect that we'll still have a long delay since we were in | |
| 2139 // dual mode before suspend. The configurator should pick up the change and | |
| 2140 // detect that we are in single display mode now. | |
| 2141 config_waiter_.Reset(); | |
| 2142 configurator_.ResumeDisplays(); | |
| 2143 EXPECT_EQ(kLongDelay, config_waiter_.Wait()); | |
| 2144 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON, | |
| 2145 configurator_.current_power_state()); | |
| 2146 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state()); | |
| 2147 EXPECT_EQ( | |
| 2148 JoinActions( | |
| 2149 kGrab, | |
| 2150 GetFramebufferAction(small_mode_.size(), outputs_[0].get(), nullptr) | |
| 2151 .c_str(), | |
| 2152 GetCrtcAction(*outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | |
| 2153 kForceDPMS, kUngrab, nullptr), | |
| 2154 log_->GetActionsAndClear()); | |
| 2155 | |
| 2156 // Verify that the above is the exact same behavior for 3+ displays. | |
| 2157 UpdateOutputs(3, true); | |
| 2158 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, | |
| 2159 configurator_.display_state()); | |
| 2160 | |
| 2161 // Suspend. | |
| 2162 config_waiter_.Reset(); | |
| 2163 configurator_.SuspendDisplays(config_waiter_.on_configuration_callback()); | |
| 2164 EXPECT_EQ(kNoDelay, config_waiter_.Wait()); | |
| 2165 EXPECT_EQ(CALLBACK_SUCCESS, config_waiter_.callback_result()); | |
| 2166 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, | |
| 2167 configurator_.display_state()); | |
| 2168 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_OFF, | |
| 2169 configurator_.current_power_state()); | |
| 2170 | |
| 2171 // Resume and expect the correct delay. | |
| 2172 config_waiter_.Reset(); | |
| 2173 configurator_.ResumeDisplays(); | |
| 2174 EXPECT_EQ(kLongDelay, config_waiter_.Wait()); | |
| 2175 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON, | |
| 2176 configurator_.current_power_state()); | |
| 2177 EXPECT_EQ(MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, | |
| 2178 configurator_.display_state()); | |
| 2179 } | |
| 2180 | |
| 2181 } // namespace test | |
| 2182 } // namespace ui | |
| OLD | NEW |