1// Copyright (c) 2012 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 "chromeos/display/output_configurator.h" 6 7#include <cmath> 8#include <cstdarg> 9#include <map> 10#include <string> 11#include <vector> 12 13#include "base/basictypes.h" 14#include "base/compiler_specific.h" 15#include "base/message_loop/message_loop.h" 16#include "base/strings/stringprintf.h" 17#include "testing/gtest/include/gtest/gtest.h" 18 19namespace chromeos { 20 21namespace { 22 23// Strings returned by TestDelegate::GetActionsAndClear() to describe various 24// actions that were performed. 25const char kInitXRandR[] = "init"; 26const char kUpdateXRandR[] = "update"; 27const char kGrab[] = "grab"; 28const char kUngrab[] = "ungrab"; 29const char kSync[] = "sync"; 30const char kForceDPMS[] = "dpms"; 31const char kProjectingOn[] = "projecting"; 32const char kProjectingOff[] = "not_projecting"; 33 34// String returned by TestDelegate::GetActionsAndClear() if no actions were 35// requested. 36const char kNoActions[] = ""; 37 38// Returns a string describing a TestDelegate::SetBackgroundColor() call. 39std::string GetBackgroundAction(uint32 color_argb) { 40 return base::StringPrintf("background(0x%x)", color_argb); 41} 42 43// Returns a string describing a TestDelegate::AddOutputMode() call. 44std::string GetAddOutputModeAction(RROutput output, RRMode mode) { 45 return base::StringPrintf("add_mode(output=%lu,mode=%lu)", output, mode); 46} 47 48// Returns a string describing a TestDelegate::ConfigureCrtc() call. 49std::string GetCrtcAction(RRCrtc crtc, 50 int x, 51 int y, 52 RRMode mode, 53 RROutput output) { 54 return base::StringPrintf("crtc(crtc=%lu,x=%d,y=%d,mode=%lu,output=%lu)", 55 crtc, x, y, mode, output); 56} 57 58// Returns a string describing a TestDelegate::CreateFramebuffer() call. 59std::string GetFramebufferAction(int width, 60 int height, 61 RRCrtc crtc1, 62 RRCrtc crtc2) { 63 return base::StringPrintf( 64 "framebuffer(width=%d,height=%d,crtc1=%lu,crtc2=%lu)", 65 width, height, crtc1, crtc2); 66} 67 68// Returns a string describing a TestDelegate::ConfigureCTM() call. 69std::string GetCTMAction( 70 int device_id, 71 const OutputConfigurator::CoordinateTransformation& ctm) { 72 return base::StringPrintf("ctm(id=%d,transform=(%f,%f,%f,%f))", device_id, 73 ctm.x_scale, ctm.x_offset, ctm.y_scale, ctm.y_offset); 74} 75 76// Returns a string describing a TestDelegate::SetHDCPState() call. 77std::string GetSetHDCPStateAction(RROutput id, HDCPState state) { 78 return base::StringPrintf("set_hdcp(id=%lu,state=%d)", id, state); 79} 80 81// Joins a sequence of strings describing actions (e.g. kScreenDim) such 82// that they can be compared against a string returned by 83// TestDelegate::GetActionsAndClear(). The list of actions must be 84// terminated by a NULL pointer. 85std::string JoinActions(const char* action, ...) { 86 std::string actions; 87 88 va_list arg_list; 89 va_start(arg_list, action); 90 while (action) { 91 if (!actions.empty()) 92 actions += ","; 93 actions += action; 94 action = va_arg(arg_list, const char*); 95 } 96 va_end(arg_list); 97 return actions; 98} 99 100class TestDelegate : public OutputConfigurator::Delegate { 101 public: 102 static const int kXRandREventBase = 10; 103 104 TestDelegate() 105 : configure_crtc_result_(true), 106 hdcp_state_(HDCP_STATE_UNDESIRED) {} 107 virtual ~TestDelegate() {} 108 109 const std::vector<OutputConfigurator::OutputSnapshot>& outputs() const { 110 return outputs_; 111 } 112 void set_outputs( 113 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { 114 outputs_ = outputs; 115 } 116 117 void set_configure_crtc_result(bool result) { 118 configure_crtc_result_ = result; 119 } 120 121 void set_hdcp_state(HDCPState state) { hdcp_state_ = state; } 122 123 // Returns a comma-separated string describing the actions that were 124 // requested since the previous call to GetActionsAndClear() (i.e. 125 // results are non-repeatable). 126 std::string GetActionsAndClear() { 127 std::string actions = actions_; 128 actions_.clear(); 129 return actions; 130 } 131 132 const OutputConfigurator::CoordinateTransformation& get_ctm( 133 int touch_device_id) { 134 return ctms_[touch_device_id]; 135 } 136 137 // OutputConfigurator::Delegate overrides: 138 virtual void InitXRandRExtension(int* event_base) OVERRIDE { 139 AppendAction(kInitXRandR); 140 *event_base = kXRandREventBase; 141 } 142 virtual void UpdateXRandRConfiguration( 143 const base::NativeEvent& event) OVERRIDE { AppendAction(kUpdateXRandR); } 144 virtual void GrabServer() OVERRIDE { AppendAction(kGrab); } 145 virtual void UngrabServer() OVERRIDE { AppendAction(kUngrab); } 146 virtual void SyncWithServer() OVERRIDE { AppendAction(kSync); } 147 virtual void SetBackgroundColor(uint32 color_argb) OVERRIDE { 148 AppendAction(GetBackgroundAction(color_argb)); 149 } 150 virtual void ForceDPMSOn() OVERRIDE { AppendAction(kForceDPMS); } 151 virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs() 152 OVERRIDE { 153 return outputs_; 154 } 155 virtual void AddOutputMode(RROutput output, RRMode mode) OVERRIDE { 156 AppendAction(GetAddOutputModeAction(output, mode)); 157 } 158 virtual bool ConfigureCrtc(RRCrtc crtc, 159 RRMode mode, 160 RROutput output, 161 int x, 162 int y) OVERRIDE { 163 AppendAction(GetCrtcAction(crtc, x, y, mode, output)); 164 return configure_crtc_result_; 165 } 166 virtual void CreateFrameBuffer( 167 int width, 168 int height, 169 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE { 170 AppendAction( 171 GetFramebufferAction(width, 172 height, 173 outputs.size() >= 1 ? outputs[0].crtc : 0, 174 outputs.size() >= 2 ? outputs[1].crtc : 0)); 175 } 176 virtual void ConfigureCTM( 177 int touch_device_id, 178 const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE { 179 AppendAction(GetCTMAction(touch_device_id, ctm)); 180 ctms_[touch_device_id] = ctm; 181 } 182 virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE { 183 AppendAction(projecting ? kProjectingOn : kProjectingOff); 184 } 185 186 virtual bool GetHDCPState(RROutput id, HDCPState* state) OVERRIDE { 187 *state = hdcp_state_; 188 return true; 189 } 190 191 virtual bool SetHDCPState(RROutput id, HDCPState state) OVERRIDE { 192 AppendAction(GetSetHDCPStateAction(id, state)); 193 return true; 194 } 195 196 private: 197 struct ModeDetails { 198 ModeDetails() : width(0), height(0), interlaced(false) {} 199 ModeDetails(int width, int height, bool interlaced) 200 : width(width), 201 height(height), 202 interlaced(interlaced) {} 203 204 int width; 205 int height; 206 bool interlaced; 207 }; 208 209 void AppendAction(const std::string& action) { 210 if (!actions_.empty()) 211 actions_ += ","; 212 actions_ += action; 213 } 214 215 std::map<RRMode, ModeDetails> modes_; 216 217 // Most-recently-configured transformation matrices, keyed by touch device ID. 218 std::map<int, OutputConfigurator::CoordinateTransformation> ctms_; 219 220 // Outputs to be returned by GetOutputs(). 221 std::vector<OutputConfigurator::OutputSnapshot> outputs_; 222 223 std::string actions_; 224 225 // Return value returned by ConfigureCrtc(). 226 bool configure_crtc_result_; 227 228 // Result value of GetHDCPState(). 229 HDCPState hdcp_state_; 230 231 DISALLOW_COPY_AND_ASSIGN(TestDelegate); 232}; 233 234class TestObserver : public OutputConfigurator::Observer { 235 public: 236 explicit TestObserver(OutputConfigurator* configurator) 237 : configurator_(configurator) { 238 Reset(); 239 configurator_->AddObserver(this); 240 } 241 virtual ~TestObserver() { 242 configurator_->RemoveObserver(this); 243 } 244 245 int num_changes() const { return num_changes_; } 246 int num_failures() const { return num_failures_; } 247 const std::vector<OutputConfigurator::OutputSnapshot>& latest_outputs() 248 const { 249 return latest_outputs_; 250 } 251 OutputState latest_failed_state() const { return latest_failed_state_; } 252 253 void Reset() { 254 num_changes_ = 0; 255 num_failures_ = 0; 256 latest_outputs_.clear(); 257 latest_failed_state_ = STATE_INVALID; 258 } 259 260 // OutputConfigurator::Observer overrides: 261 virtual void OnDisplayModeChanged( 262 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE { 263 num_changes_++; 264 latest_outputs_ = outputs; 265 } 266 267 virtual void OnDisplayModeChangeFailed(OutputState failed_new_state) 268 OVERRIDE { 269 num_failures_++; 270 latest_failed_state_ = failed_new_state; 271 } 272 273 private: 274 OutputConfigurator* configurator_; // Not owned. 275 276 // Number of times that OnDisplayMode*() has been called. 277 int num_changes_; 278 int num_failures_; 279 280 // Parameters most recently passed to OnDisplayMode*(). 281 std::vector<OutputConfigurator::OutputSnapshot> latest_outputs_; 282 OutputState latest_failed_state_; 283 284 DISALLOW_COPY_AND_ASSIGN(TestObserver); 285}; 286 287class TestStateController : public OutputConfigurator::StateController { 288 public: 289 TestStateController() : state_(STATE_DUAL_EXTENDED) {} 290 virtual ~TestStateController() {} 291 292 void set_state(OutputState state) { state_ = state; } 293 294 // OutputConfigurator::StateController overrides: 295 virtual OutputState GetStateForDisplayIds( 296 const std::vector<int64>& outputs) const OVERRIDE { return state_; } 297 virtual bool GetResolutionForDisplayId( 298 int64 display_id, 299 int *width, 300 int *height) const OVERRIDE { 301 return false; 302 } 303 304 private: 305 OutputState state_; 306 307 DISALLOW_COPY_AND_ASSIGN(TestStateController); 308}; 309 310class TestMirroringController 311 : public OutputConfigurator::SoftwareMirroringController { 312 public: 313 TestMirroringController() : software_mirroring_enabled_(false) {} 314 virtual ~TestMirroringController() {} 315 316 virtual void SetSoftwareMirroring(bool enabled) OVERRIDE { 317 software_mirroring_enabled_ = enabled; 318 } 319 320 bool software_mirroring_enabled() const { 321 return software_mirroring_enabled_; 322 } 323 324 private: 325 bool software_mirroring_enabled_; 326 327 DISALLOW_COPY_AND_ASSIGN(TestMirroringController); 328}; 329 330class OutputConfiguratorTest : public testing::Test { 331 public: 332 // Predefined modes that can be used by outputs. 333 static const RRMode kSmallModeId; 334 static const int kSmallModeWidth; 335 static const int kSmallModeHeight; 336 337 static const RRMode kBigModeId; 338 static const int kBigModeWidth; 339 static const int kBigModeHeight; 340 341 OutputConfiguratorTest() 342 : observer_(&configurator_), 343 test_api_(&configurator_, TestDelegate::kXRandREventBase) {} 344 virtual ~OutputConfiguratorTest() {} 345 346 virtual void SetUp() OVERRIDE { 347 delegate_ = new TestDelegate(); 348 configurator_.SetDelegateForTesting( 349 scoped_ptr<OutputConfigurator::Delegate>(delegate_)); 350 configurator_.set_state_controller(&state_controller_); 351 configurator_.set_mirroring_controller(&mirroring_controller_); 352 353 OutputConfigurator::ModeInfo small_mode_info; 354 small_mode_info.width = kSmallModeWidth; 355 small_mode_info.height = kSmallModeHeight; 356 357 OutputConfigurator::ModeInfo big_mode_info; 358 big_mode_info.width = kBigModeWidth; 359 big_mode_info.height = kBigModeHeight; 360 361 OutputConfigurator::OutputSnapshot* o = &outputs_[0]; 362 o->output = 1; 363 o->crtc = 10; 364 o->current_mode = kSmallModeId; 365 o->native_mode = kSmallModeId; 366 o->is_internal = true; 367 o->type = OUTPUT_TYPE_INTERNAL; 368 o->is_aspect_preserving_scaling = true; 369 o->mode_infos[kSmallModeId] = small_mode_info; 370 o->has_display_id = true; 371 o->display_id = 123; 372 o->index = 0; 373 374 o = &outputs_[1]; 375 o->output = 2; 376 o->crtc = 11; 377 o->current_mode = kBigModeId; 378 o->native_mode = kBigModeId; 379 o->is_internal = false; 380 o->type = OUTPUT_TYPE_HDMI; 381 o->is_aspect_preserving_scaling = true; 382 o->mode_infos[kSmallModeId] = small_mode_info; 383 o->mode_infos[kBigModeId] = big_mode_info; 384 o->has_display_id = true; 385 o->display_id = 456; 386 o->index = 1; 387 388 UpdateOutputs(2, false); 389 } 390 391 protected: 392 // Configures |delegate_| to return the first |num_outputs| entries from 393 // |outputs_|. If |send_events| is true, also sends screen-change and 394 // output-change events to |configurator_| and triggers the configure 395 // timeout if one was scheduled. 396 void UpdateOutputs(size_t num_outputs, bool send_events) { 397 ASSERT_LE(num_outputs, arraysize(outputs_)); 398 std::vector<OutputConfigurator::OutputSnapshot> outputs; 399 for (size_t i = 0; i < num_outputs; ++i) 400 outputs.push_back(outputs_[i]); 401 delegate_->set_outputs(outputs); 402 403 if (send_events) { 404 test_api_.SendScreenChangeEvent(); 405 for (size_t i = 0; i < arraysize(outputs_); ++i) { 406 const OutputConfigurator::OutputSnapshot output = outputs_[i]; 407 bool connected = i < num_outputs; 408 test_api_.SendOutputChangeEvent( 409 output.output, output.crtc, output.current_mode, connected); 410 } 411 test_api_.TriggerConfigureTimeout(); 412 } 413 } 414 415 // Initializes |configurator_| with a single internal display. 416 void InitWithSingleOutput() { 417 UpdateOutputs(1, false); 418 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 419 configurator_.Init(false); 420 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 421 configurator_.Start(0); 422 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, 423 GetFramebufferAction(kSmallModeWidth, 424 kSmallModeHeight, outputs_[0].crtc, 0).c_str(), 425 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 426 outputs_[0].output).c_str(), 427 kForceDPMS, kUngrab, kProjectingOff, NULL), 428 delegate_->GetActionsAndClear()); 429 } 430 431 base::MessageLoop message_loop_; 432 TestStateController state_controller_; 433 TestMirroringController mirroring_controller_; 434 OutputConfigurator configurator_; 435 TestObserver observer_; 436 TestDelegate* delegate_; // not owned 437 OutputConfigurator::TestApi test_api_; 438 439 OutputConfigurator::OutputSnapshot outputs_[2]; 440 441 private: 442 DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest); 443}; 444 445const RRMode OutputConfiguratorTest::kSmallModeId = 20; 446const int OutputConfiguratorTest::kSmallModeWidth = 1366; 447const int OutputConfiguratorTest::kSmallModeHeight = 768; 448 449const RRMode OutputConfiguratorTest::kBigModeId = 21; 450const int OutputConfiguratorTest::kBigModeWidth = 2560; 451const int OutputConfiguratorTest::kBigModeHeight = 1600; 452 453} // namespace 454 455TEST_F(OutputConfiguratorTest, FindOutputModeMatchingSize) { 456 OutputConfigurator::OutputSnapshot output; 457 458 // Fields are width, height, interlaced, refresh rate. 459 output.mode_infos[11] = OutputConfigurator::ModeInfo(1920, 1200, false, 60.0); 460 // Different rates. 461 output.mode_infos[12] = OutputConfigurator::ModeInfo(1920, 1080, false, 30.0); 462 output.mode_infos[13] = OutputConfigurator::ModeInfo(1920, 1080, false, 50.0); 463 output.mode_infos[14] = OutputConfigurator::ModeInfo(1920, 1080, false, 40.0); 464 output.mode_infos[15] = OutputConfigurator::ModeInfo(1920, 1080, false, 0.0); 465 // Interlaced vs non-interlaced. 466 output.mode_infos[16] = OutputConfigurator::ModeInfo(1280, 720, true, 60.0); 467 output.mode_infos[17] = OutputConfigurator::ModeInfo(1280, 720, false, 40.0); 468 // Interlaced only. 469 output.mode_infos[18] = OutputConfigurator::ModeInfo(1024, 768, true, 0.0); 470 output.mode_infos[19] = OutputConfigurator::ModeInfo(1024, 768, true, 40.0); 471 output.mode_infos[20] = OutputConfigurator::ModeInfo(1024, 768, true, 60.0); 472 // Mixed. 473 output.mode_infos[21] = OutputConfigurator::ModeInfo(1024, 600, true, 60.0); 474 output.mode_infos[22] = OutputConfigurator::ModeInfo(1024, 600, false, 40.0); 475 output.mode_infos[23] = OutputConfigurator::ModeInfo(1024, 600, false, 50.0); 476 // Just one interlaced mode. 477 output.mode_infos[24] = OutputConfigurator::ModeInfo(640, 480, true, 60.0); 478 // Refresh rate not available. 479 output.mode_infos[25] = OutputConfigurator::ModeInfo(320, 200, false, 0.0); 480 481 EXPECT_EQ(11u, OutputConfigurator::FindOutputModeMatchingSize(output, 482 1920, 1200)); 483 484 // Should pick highest refresh rate. 485 EXPECT_EQ(13u, OutputConfigurator::FindOutputModeMatchingSize(output, 486 1920, 1080)); 487 488 // Should pick non-interlaced mode. 489 EXPECT_EQ(17u, OutputConfigurator::FindOutputModeMatchingSize(output, 490 1280, 720)); 491 492 // Interlaced only. Should pick one with the highest refresh rate in 493 // interlaced mode. 494 EXPECT_EQ(20u, OutputConfigurator::FindOutputModeMatchingSize(output, 495 1024, 768)); 496 497 // Mixed: Should pick one with the highest refresh rate in 498 // interlaced mode. 499 EXPECT_EQ(23u, OutputConfigurator::FindOutputModeMatchingSize(output, 500 1024, 600)); 501 502 // Just one interlaced mode. 503 EXPECT_EQ(24u, OutputConfigurator::FindOutputModeMatchingSize(output, 504 640, 480)); 505 506 // Refresh rate not available. 507 EXPECT_EQ(25u, OutputConfigurator::FindOutputModeMatchingSize(output, 508 320, 200)); 509 510 // No mode found. 511 EXPECT_EQ(0u, OutputConfigurator::FindOutputModeMatchingSize(output, 512 1440, 900)); 513} 514 515TEST_F(OutputConfiguratorTest, ConnectSecondOutput) { 516 InitWithSingleOutput(); 517 518 // Connect a second output and check that the configurator enters 519 // extended mode. 520 observer_.Reset(); 521 state_controller_.set_state(STATE_DUAL_EXTENDED); 522 UpdateOutputs(2, true); 523 const int kDualHeight = 524 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight; 525 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 526 GetFramebufferAction(kBigModeWidth, kDualHeight, 527 outputs_[0].crtc, outputs_[1].crtc).c_str(), 528 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 529 outputs_[0].output).c_str(), 530 GetCrtcAction(outputs_[1].crtc, 0, 531 kSmallModeHeight + OutputConfigurator::kVerticalGap, 532 kBigModeId, outputs_[1].output).c_str(), 533 kUngrab, kProjectingOn, NULL), 534 delegate_->GetActionsAndClear()); 535 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 536 EXPECT_EQ(1, observer_.num_changes()); 537 538 observer_.Reset(); 539 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR)); 540 EXPECT_EQ(JoinActions(kGrab, 541 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 542 outputs_[0].crtc, outputs_[1].crtc).c_str(), 543 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 544 outputs_[0].output).c_str(), 545 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 546 outputs_[1].output).c_str(), 547 kUngrab, NULL), 548 delegate_->GetActionsAndClear()); 549 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 550 EXPECT_EQ(1, observer_.num_changes()); 551 552 // Disconnect the second output. 553 observer_.Reset(); 554 UpdateOutputs(1, true); 555 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 556 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 557 outputs_[0].crtc, 0).c_str(), 558 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 559 outputs_[0].output).c_str(), 560 kUngrab, kProjectingOff, NULL), 561 delegate_->GetActionsAndClear()); 562 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 563 EXPECT_EQ(1, observer_.num_changes()); 564 565 // Get rid of shared modes to force software mirroring. 566 outputs_[1].mode_infos.erase(kSmallModeId); 567 state_controller_.set_state(STATE_DUAL_EXTENDED); 568 UpdateOutputs(2, true); 569 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 570 GetFramebufferAction(kBigModeWidth, kDualHeight, 571 outputs_[0].crtc, outputs_[1].crtc).c_str(), 572 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 573 outputs_[0].output).c_str(), 574 GetCrtcAction(outputs_[1].crtc, 0, 575 kSmallModeHeight + OutputConfigurator::kVerticalGap, 576 kBigModeId, outputs_[1].output).c_str(), 577 kUngrab, kProjectingOn, NULL), 578 delegate_->GetActionsAndClear()); 579 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 580 581 observer_.Reset(); 582 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR)); 583 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear()); 584 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state()); 585 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled()); 586 EXPECT_EQ(1, observer_.num_changes()); 587 588 // Setting STATE_DUAL_MIRROR should try to reconfigure. 589 observer_.Reset(); 590 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED)); 591 EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear()); 592 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 593 EXPECT_EQ(1, observer_.num_changes()); 594 595 // Set back to software mirror mode. 596 observer_.Reset(); 597 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR)); 598 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), 599 delegate_->GetActionsAndClear()); 600 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state()); 601 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled()); 602 EXPECT_EQ(1, observer_.num_changes()); 603 604 // Disconnect the second output. 605 observer_.Reset(); 606 UpdateOutputs(1, true); 607 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 608 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 609 outputs_[0].crtc, 0).c_str(), 610 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 611 outputs_[0].output).c_str(), 612 kUngrab, kProjectingOff, NULL), 613 delegate_->GetActionsAndClear()); 614 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 615 EXPECT_EQ(1, observer_.num_changes()); 616} 617 618TEST_F(OutputConfiguratorTest, SetDisplayPower) { 619 InitWithSingleOutput(); 620 621 state_controller_.set_state(STATE_DUAL_MIRROR); 622 observer_.Reset(); 623 UpdateOutputs(2, true); 624 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 625 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 626 outputs_[0].crtc, outputs_[1].crtc).c_str(), 627 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 628 outputs_[0].output).c_str(), 629 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 630 outputs_[1].output).c_str(), 631 kUngrab, kProjectingOn, NULL), 632 delegate_->GetActionsAndClear()); 633 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 634 EXPECT_EQ(1, observer_.num_changes()); 635 636 // Turning off the internal display should switch the external display to 637 // its native mode. 638 observer_.Reset(); 639 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, 640 OutputConfigurator::kSetDisplayPowerNoFlags); 641 EXPECT_EQ(JoinActions(kGrab, 642 GetFramebufferAction(kBigModeWidth, kBigModeHeight, 643 outputs_[0].crtc, outputs_[1].crtc).c_str(), 644 GetCrtcAction(outputs_[0].crtc, 0, 0, 0, 645 outputs_[0].output).c_str(), 646 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId, 647 outputs_[1].output).c_str(), 648 kForceDPMS, kUngrab, NULL), 649 delegate_->GetActionsAndClear()); 650 EXPECT_EQ(STATE_SINGLE, configurator_.output_state()); 651 EXPECT_EQ(1, observer_.num_changes()); 652 653 // When all displays are turned off, the framebuffer should switch back 654 // to the mirrored size. 655 observer_.Reset(); 656 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF, 657 OutputConfigurator::kSetDisplayPowerNoFlags); 658 EXPECT_EQ(JoinActions(kGrab, 659 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 660 outputs_[0].crtc, outputs_[1].crtc).c_str(), 661 GetCrtcAction(outputs_[0].crtc, 0, 0, 0, 662 outputs_[0].output).c_str(), 663 GetCrtcAction(outputs_[1].crtc, 0, 0, 0, 664 outputs_[1].output).c_str(), 665 kUngrab, NULL), 666 delegate_->GetActionsAndClear()); 667 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state()); 668 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 669 EXPECT_EQ(1, observer_.num_changes()); 670 671 // Turn all displays on and check that mirroring is still used. 672 observer_.Reset(); 673 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON, 674 OutputConfigurator::kSetDisplayPowerNoFlags); 675 EXPECT_EQ(JoinActions(kGrab, 676 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 677 outputs_[0].crtc, outputs_[1].crtc).c_str(), 678 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 679 outputs_[0].output).c_str(), 680 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 681 outputs_[1].output).c_str(), 682 kForceDPMS, kUngrab, NULL), 683 delegate_->GetActionsAndClear()); 684 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state()); 685 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 686 EXPECT_EQ(1, observer_.num_changes()); 687 688 // Get rid of shared modes to force software mirroring. 689 outputs_[1].mode_infos.erase(kSmallModeId); 690 state_controller_.set_state(STATE_DUAL_MIRROR); 691 observer_.Reset(); 692 UpdateOutputs(2, true); 693 const int kDualHeight = 694 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight; 695 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 696 GetFramebufferAction(kBigModeWidth, kDualHeight, 697 outputs_[0].crtc, outputs_[1].crtc).c_str(), 698 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 699 outputs_[0].output).c_str(), 700 GetCrtcAction(outputs_[1].crtc, 0, 701 kSmallModeHeight + OutputConfigurator::kVerticalGap, 702 kBigModeId, outputs_[1].output).c_str(), 703 kUngrab, kProjectingOn, NULL), 704 delegate_->GetActionsAndClear()); 705 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state()); 706 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled()); 707 EXPECT_EQ(1, observer_.num_changes()); 708 709 // Turning off the internal display should switch the external display to 710 // its native mode. 711 observer_.Reset(); 712 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, 713 OutputConfigurator::kSetDisplayPowerNoFlags); 714 EXPECT_EQ(JoinActions(kGrab, 715 GetFramebufferAction(kBigModeWidth, kBigModeHeight, 716 outputs_[0].crtc, outputs_[1].crtc).c_str(), 717 GetCrtcAction(outputs_[0].crtc, 0, 0, 0, 718 outputs_[0].output).c_str(), 719 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId, 720 outputs_[1].output).c_str(), 721 kForceDPMS, kUngrab, NULL), 722 delegate_->GetActionsAndClear()); 723 EXPECT_EQ(STATE_SINGLE, configurator_.output_state()); 724 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled()); 725 EXPECT_EQ(1, observer_.num_changes()); 726 727 // When all displays are turned off, the framebuffer should switch back 728 // to the extended + software mirroring. 729 observer_.Reset(); 730 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF, 731 OutputConfigurator::kSetDisplayPowerNoFlags); 732 EXPECT_EQ(JoinActions(kGrab, 733 GetFramebufferAction(kBigModeWidth, kDualHeight, 734 outputs_[0].crtc, outputs_[1].crtc).c_str(), 735 GetCrtcAction(outputs_[0].crtc, 0, 0, 0, 736 outputs_[0].output).c_str(), 737 GetCrtcAction(outputs_[1].crtc, 0, 738 kSmallModeHeight + OutputConfigurator::kVerticalGap, 739 0, outputs_[1].output).c_str(), 740 kUngrab, NULL), 741 delegate_->GetActionsAndClear()); 742 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state()); 743 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled()); 744 EXPECT_EQ(1, observer_.num_changes()); 745 746 // Turn all displays on and check that mirroring is still used. 747 observer_.Reset(); 748 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON, 749 OutputConfigurator::kSetDisplayPowerNoFlags); 750 EXPECT_EQ(JoinActions(kGrab, 751 GetFramebufferAction(kBigModeWidth, kDualHeight, 752 outputs_[0].crtc, outputs_[1].crtc).c_str(), 753 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 754 outputs_[0].output).c_str(), 755 GetCrtcAction(outputs_[1].crtc, 0, 756 kSmallModeHeight + OutputConfigurator::kVerticalGap, 757 kBigModeId, outputs_[1].output).c_str(), 758 kForceDPMS, kUngrab, NULL), 759 delegate_->GetActionsAndClear()); 760 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state()); 761 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled()); 762 EXPECT_EQ(1, observer_.num_changes()); 763} 764 765TEST_F(OutputConfiguratorTest, SuspendAndResume) { 766 InitWithSingleOutput(); 767 768 // No preparation is needed before suspending when the display is already 769 // on. The configurator should still reprobe on resume in case a display 770 // was connected while suspended. 771 configurator_.SuspendDisplays(); 772 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 773 configurator_.ResumeDisplays(); 774 EXPECT_EQ(JoinActions(kGrab, 775 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 776 outputs_[0].crtc, 0).c_str(), 777 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 778 outputs_[0].output).c_str(), 779 kForceDPMS, kUngrab, NULL), 780 delegate_->GetActionsAndClear()); 781 782 // Now turn the display off before suspending and check that the 783 // configurator turns it back on and syncs with the server. 784 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF, 785 OutputConfigurator::kSetDisplayPowerNoFlags); 786 EXPECT_EQ(JoinActions(kGrab, 787 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 788 outputs_[0].crtc, 0).c_str(), 789 GetCrtcAction(outputs_[0].crtc, 0, 0, 0, 790 outputs_[0].output).c_str(), 791 kUngrab, NULL), 792 delegate_->GetActionsAndClear()); 793 794 configurator_.SuspendDisplays(); 795 EXPECT_EQ(JoinActions(kGrab, 796 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 797 outputs_[0].crtc, 0).c_str(), 798 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 799 outputs_[0].output).c_str(), 800 kForceDPMS, kUngrab, kSync, NULL), 801 delegate_->GetActionsAndClear()); 802 803 configurator_.ResumeDisplays(); 804 EXPECT_EQ(JoinActions(kGrab, 805 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 806 outputs_[0].crtc, 0).c_str(), 807 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 808 outputs_[0].output).c_str(), 809 kForceDPMS, kUngrab, NULL), 810 delegate_->GetActionsAndClear()); 811 812 // If a second, external display is connected, the displays shouldn't be 813 // powered back on before suspending. 814 state_controller_.set_state(STATE_DUAL_MIRROR); 815 UpdateOutputs(2, true); 816 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 817 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 818 outputs_[0].crtc, outputs_[1].crtc).c_str(), 819 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 820 outputs_[0].output).c_str(), 821 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 822 outputs_[1].output).c_str(), 823 kUngrab, kProjectingOn, NULL), 824 delegate_->GetActionsAndClear()); 825 826 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF, 827 OutputConfigurator::kSetDisplayPowerNoFlags); 828 EXPECT_EQ(JoinActions(kGrab, 829 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 830 outputs_[0].crtc, outputs_[1].crtc).c_str(), 831 GetCrtcAction(outputs_[0].crtc, 0, 0, 0, 832 outputs_[0].output).c_str(), 833 GetCrtcAction(outputs_[1].crtc, 0, 0, 0, 834 outputs_[1].output).c_str(), 835 kUngrab, NULL), 836 delegate_->GetActionsAndClear()); 837 838 configurator_.SuspendDisplays(); 839 EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL), 840 delegate_->GetActionsAndClear()); 841 842 // If a display is disconnected while suspended, the configurator should 843 // pick up the change. 844 UpdateOutputs(1, false); 845 configurator_.ResumeDisplays(); 846 EXPECT_EQ(JoinActions(kGrab, 847 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 848 outputs_[0].crtc, 0).c_str(), 849 GetCrtcAction(outputs_[0].crtc, 0, 0, 0, 850 outputs_[0].output).c_str(), 851 kUngrab, NULL), 852 delegate_->GetActionsAndClear()); 853} 854 855TEST_F(OutputConfiguratorTest, Headless) { 856 UpdateOutputs(0, false); 857 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 858 configurator_.Init(false); 859 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 860 configurator_.Start(0); 861 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab, 862 kProjectingOff, NULL), 863 delegate_->GetActionsAndClear()); 864 865 // Not much should happen when the display power state is changed while 866 // no displays are connected. 867 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF, 868 OutputConfigurator::kSetDisplayPowerNoFlags); 869 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear()); 870 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON, 871 OutputConfigurator::kSetDisplayPowerNoFlags); 872 EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL), 873 delegate_->GetActionsAndClear()); 874 875 // Connect an external display and check that it's configured correctly. 876 outputs_[0] = outputs_[1]; 877 UpdateOutputs(1, true); 878 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 879 GetFramebufferAction(kBigModeWidth, kBigModeHeight, 880 outputs_[0].crtc, 0).c_str(), 881 GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId, 882 outputs_[0].output).c_str(), 883 kUngrab, kProjectingOff, NULL), 884 delegate_->GetActionsAndClear()); 885} 886 887TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) { 888 UpdateOutputs(2, false); 889 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 890 configurator_.Init(false); 891 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 892 893 state_controller_.set_state(STATE_DUAL_MIRROR); 894 configurator_.Start(0); 895 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, 896 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 897 outputs_[0].crtc, outputs_[1].crtc).c_str(), 898 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 899 outputs_[0].output).c_str(), 900 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 901 outputs_[1].output).c_str(), 902 kForceDPMS, kUngrab, kProjectingOn, NULL), 903 delegate_->GetActionsAndClear()); 904} 905 906TEST_F(OutputConfiguratorTest, InvalidOutputStates) { 907 UpdateOutputs(0, false); 908 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 909 configurator_.Init(false); 910 configurator_.Start(0); 911 observer_.Reset(); 912 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS)); 913 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE)); 914 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR)); 915 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED)); 916 EXPECT_EQ(1, observer_.num_changes()); 917 EXPECT_EQ(3, observer_.num_failures()); 918 919 UpdateOutputs(1, true); 920 observer_.Reset(); 921 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS)); 922 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE)); 923 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR)); 924 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED)); 925 EXPECT_EQ(1, observer_.num_changes()); 926 EXPECT_EQ(3, observer_.num_failures()); 927 928 state_controller_.set_state(STATE_DUAL_EXTENDED); 929 UpdateOutputs(2, true); 930 observer_.Reset(); 931 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS)); 932 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE)); 933 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR)); 934 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED)); 935 EXPECT_EQ(2, observer_.num_changes()); 936 EXPECT_EQ(2, observer_.num_failures()); 937} 938 939TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithoutId) { 940 outputs_[0].has_display_id = false; 941 UpdateOutputs(2, false); 942 configurator_.Init(false); 943 state_controller_.set_state(STATE_DUAL_MIRROR); 944 configurator_.Start(0); 945 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state()); 946} 947 948TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithId) { 949 outputs_[0].has_display_id = true; 950 UpdateOutputs(2, false); 951 configurator_.Init(false); 952 state_controller_.set_state(STATE_DUAL_MIRROR); 953 configurator_.Start(0); 954 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state()); 955} 956 957TEST_F(OutputConfiguratorTest, AvoidUnnecessaryProbes) { 958 InitWithSingleOutput(); 959 960 // X sends several events just after the configurator starts. Check that 961 // the output change events don't trigger an additional probe, which can 962 // block the UI thread. 963 test_api_.SendScreenChangeEvent(); 964 EXPECT_EQ(kUpdateXRandR, delegate_->GetActionsAndClear()); 965 966 test_api_.SendOutputChangeEvent( 967 outputs_[0].output, outputs_[0].crtc, outputs_[0].current_mode, true); 968 test_api_.SendOutputChangeEvent( 969 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false); 970 EXPECT_FALSE(test_api_.TriggerConfigureTimeout()); 971 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 972 973 // Send an event stating that the second output is connected and check 974 // that it gets updated. 975 state_controller_.set_state(STATE_DUAL_MIRROR); 976 UpdateOutputs(2, false); 977 test_api_.SendOutputChangeEvent( 978 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, true); 979 EXPECT_TRUE(test_api_.TriggerConfigureTimeout()); 980 EXPECT_EQ(JoinActions(kGrab, 981 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 982 outputs_[0].crtc, outputs_[1].crtc).c_str(), 983 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 984 outputs_[0].output).c_str(), 985 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 986 outputs_[1].output).c_str(), 987 kUngrab, kProjectingOn, NULL), 988 delegate_->GetActionsAndClear()); 989 990 // An event about the second output changing modes should trigger another 991 // reconfigure. 992 test_api_.SendOutputChangeEvent( 993 outputs_[1].output, outputs_[1].crtc, outputs_[1].native_mode, true); 994 EXPECT_TRUE(test_api_.TriggerConfigureTimeout()); 995 EXPECT_EQ(JoinActions(kGrab, 996 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 997 outputs_[0].crtc, outputs_[1].crtc).c_str(), 998 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 999 outputs_[0].output).c_str(), 1000 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 1001 outputs_[1].output).c_str(), 1002 kUngrab, kProjectingOn, NULL), 1003 delegate_->GetActionsAndClear()); 1004 1005 // Disconnect the second output. 1006 UpdateOutputs(1, true); 1007 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 1008 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 1009 outputs_[0].crtc, 0).c_str(), 1010 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 1011 outputs_[0].output).c_str(), 1012 kUngrab, kProjectingOff, NULL), 1013 delegate_->GetActionsAndClear()); 1014 1015 // An additional event about the second output being disconnected should 1016 // be ignored. 1017 test_api_.SendOutputChangeEvent( 1018 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false); 1019 EXPECT_FALSE(test_api_.TriggerConfigureTimeout()); 1020 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 1021 1022 // Tell the delegate to report failure, which should result in the 1023 // second output sticking with its native mode. 1024 delegate_->set_configure_crtc_result(false); 1025 UpdateOutputs(2, true); 1026 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, 1027 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 1028 outputs_[0].crtc, outputs_[1].crtc).c_str(), 1029 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 1030 outputs_[0].output).c_str(), 1031 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 1032 outputs_[1].output).c_str(), 1033 kUngrab, kProjectingOn, NULL), 1034 delegate_->GetActionsAndClear()); 1035 1036 // An change event reporting a mode change on the second output should 1037 // trigger another reconfigure. 1038 delegate_->set_configure_crtc_result(true); 1039 test_api_.SendOutputChangeEvent( 1040 outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true); 1041 EXPECT_TRUE(test_api_.TriggerConfigureTimeout()); 1042 EXPECT_EQ(JoinActions(kGrab, 1043 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 1044 outputs_[0].crtc, outputs_[1].crtc).c_str(), 1045 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 1046 outputs_[0].output).c_str(), 1047 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 1048 outputs_[1].output).c_str(), 1049 kUngrab, kProjectingOn, NULL), 1050 delegate_->GetActionsAndClear()); 1051} 1052 1053TEST_F(OutputConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) { 1054 InitWithSingleOutput(); 1055 const std::vector<OutputConfigurator::OutputSnapshot>* cached = 1056 &test_api_.cached_outputs(); 1057 ASSERT_EQ(static_cast<size_t>(1), cached->size()); 1058 EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode); 1059 1060 // After connecting a second output, check that it shows up in 1061 // |cached_outputs_| even if an invalid state is requested. 1062 state_controller_.set_state(STATE_SINGLE); 1063 UpdateOutputs(2, true); 1064 cached = &test_api_.cached_outputs(); 1065 ASSERT_EQ(static_cast<size_t>(2), cached->size()); 1066 EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode); 1067 EXPECT_EQ(outputs_[1].current_mode, (*cached)[1].current_mode); 1068} 1069 1070TEST_F(OutputConfiguratorTest, PanelFitting) { 1071 // Configure the internal display to support only the big mode and the 1072 // external display to support only the small mode. 1073 outputs_[0].current_mode = kBigModeId; 1074 outputs_[0].native_mode = kBigModeId; 1075 outputs_[0].mode_infos.clear(); 1076 outputs_[0].mode_infos[kBigModeId] = OutputConfigurator::ModeInfo( 1077 kBigModeWidth, kBigModeHeight, false, 60.0); 1078 1079 outputs_[1].current_mode = kSmallModeId; 1080 outputs_[1].native_mode = kSmallModeId; 1081 outputs_[1].mode_infos.clear(); 1082 outputs_[1].mode_infos[kSmallModeId] = OutputConfigurator::ModeInfo( 1083 kSmallModeWidth, kSmallModeHeight, false, 60.0); 1084 1085 // The small mode should be added to the internal output when requesting 1086 // mirrored mode. 1087 UpdateOutputs(2, false); 1088 state_controller_.set_state(STATE_DUAL_MIRROR); 1089 configurator_.Init(true /* is_panel_fitting_enabled */); 1090 configurator_.Start(0); 1091 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state()); 1092 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, 1093 GetAddOutputModeAction( 1094 outputs_[0].output, kSmallModeId).c_str(), 1095 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, 1096 outputs_[0].crtc, outputs_[1].crtc).c_str(), 1097 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, 1098 outputs_[0].output).c_str(), 1099 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, 1100 outputs_[1].output).c_str(), 1101 kForceDPMS, kUngrab, kProjectingOn, NULL), 1102 delegate_->GetActionsAndClear()); 1103 1104 // Both outputs should be using the small mode. 1105 ASSERT_EQ(1, observer_.num_changes()); 1106 ASSERT_EQ(static_cast<size_t>(2), observer_.latest_outputs().size()); 1107 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].mirror_mode); 1108 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].current_mode); 1109 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].mirror_mode); 1110 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].current_mode); 1111 1112 // Also check that the newly-added small mode is present in the internal 1113 // snapshot that was passed to the observer (http://crbug.com/289159). 1114 const OutputConfigurator::ModeInfo* info = OutputConfigurator::GetModeInfo( 1115 observer_.latest_outputs()[0], kSmallModeId); 1116 ASSERT_TRUE(info); 1117 EXPECT_EQ(kSmallModeWidth, info->width); 1118 EXPECT_EQ(kSmallModeHeight, info->height); 1119} 1120 1121TEST_F(OutputConfiguratorTest, OutputProtection) { 1122 configurator_.Init(false); 1123 configurator_.Start(0); 1124 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear()); 1125 1126 OutputConfigurator::OutputProtectionClientId id = 1127 configurator_.RegisterOutputProtectionClient(); 1128 EXPECT_NE(0u, id); 1129 1130 // One output. 1131 UpdateOutputs(1, true); 1132 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear()); 1133 uint32_t link_mask = 0; 1134 uint32_t protection_mask = 0; 1135 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, 1136 outputs_[0].display_id, 1137 &link_mask, 1138 &protection_mask)); 1139 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL), link_mask); 1140 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE), 1141 protection_mask); 1142 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 1143 1144 // Two outputs. 1145 UpdateOutputs(2, true); 1146 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear()); 1147 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, 1148 outputs_[1].display_id, 1149 &link_mask, 1150 &protection_mask)); 1151 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), 1152 link_mask); 1153 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE), 1154 protection_mask); 1155 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 1156 1157 EXPECT_TRUE( 1158 configurator_.EnableOutputProtection(id, 1159 outputs_[1].display_id, 1160 OUTPUT_PROTECTION_METHOD_HDCP)); 1161 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_DESIRED), 1162 delegate_->GetActionsAndClear()); 1163 1164 // Enable protection. 1165 delegate_->set_hdcp_state(HDCP_STATE_ENABLED); 1166 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, 1167 outputs_[1].display_id, 1168 &link_mask, 1169 &protection_mask)); 1170 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask); 1171 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP), 1172 protection_mask); 1173 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); 1174 1175 // Protections should be disabled after unregister. 1176 configurator_.UnregisterOutputProtectionClient(id); 1177 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_UNDESIRED), 1178 delegate_->GetActionsAndClear()); 1179} 1180 1181TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) { 1182 OutputConfigurator::OutputProtectionClientId client1 = 1183 configurator_.RegisterOutputProtectionClient(); 1184 OutputConfigurator::OutputProtectionClientId client2 = 1185 configurator_.RegisterOutputProtectionClient(); 1186 EXPECT_NE(client1, client2); 1187 1188 configurator_.Init(false); 1189 configurator_.Start(0); 1190 UpdateOutputs(2, true); 1191 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear()); 1192 1193 // Clients never know state enableness for methods that they didn't request. 1194 EXPECT_TRUE( 1195 configurator_.EnableOutputProtection(client1, 1196 outputs_[1].display_id, 1197 OUTPUT_PROTECTION_METHOD_HDCP)); 1198 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, 1199 HDCP_STATE_DESIRED).c_str(), 1200 delegate_->GetActionsAndClear()); 1201 delegate_->set_hdcp_state(HDCP_STATE_ENABLED); 1202 1203 uint32_t link_mask = 0; 1204 uint32_t protection_mask = 0; 1205 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client1, 1206 outputs_[1].display_id, 1207 &link_mask, 1208 &protection_mask)); 1209 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask); 1210 EXPECT_EQ(OUTPUT_PROTECTION_METHOD_HDCP, protection_mask); 1211 1212 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client2, 1213 outputs_[1].display_id, 1214 &link_mask, 1215 &protection_mask)); 1216 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask); 1217 EXPECT_EQ(OUTPUT_PROTECTION_METHOD_NONE, protection_mask); 1218 1219 // Protections will be disabled only if no more clients request them. 1220 EXPECT_TRUE( 1221 configurator_.EnableOutputProtection(client2, 1222 outputs_[1].display_id, 1223 OUTPUT_PROTECTION_METHOD_NONE)); 1224 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, 1225 HDCP_STATE_DESIRED).c_str(), 1226 delegate_->GetActionsAndClear()); 1227 EXPECT_TRUE( 1228 configurator_.EnableOutputProtection(client1, 1229 outputs_[1].display_id, 1230 OUTPUT_PROTECTION_METHOD_NONE)); 1231 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, 1232 HDCP_STATE_UNDESIRED).c_str(), 1233 delegate_->GetActionsAndClear()); 1234} 1235 1236TEST_F(OutputConfiguratorTest, CTMForMultiScreens) { 1237 outputs_[0].touch_device_id = 1; 1238 outputs_[1].touch_device_id = 2; 1239 1240 UpdateOutputs(2, false); 1241 configurator_.Init(false); 1242 state_controller_.set_state(STATE_DUAL_EXTENDED); 1243 configurator_.Start(0); 1244 1245 const int kDualHeight = 1246 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight; 1247 const int kDualWidth = kBigModeWidth; 1248 1249 OutputConfigurator::CoordinateTransformation ctm1 = delegate_->get_ctm(1); 1250 OutputConfigurator::CoordinateTransformation ctm2 = delegate_->get_ctm(2); 1251 1252 EXPECT_EQ(kSmallModeHeight - 1, round((kDualHeight - 1) * ctm1.y_scale)); 1253 EXPECT_EQ(0, round((kDualHeight - 1) * ctm1.y_offset)); 1254 1255 EXPECT_EQ(kBigModeHeight - 1, round((kDualHeight - 1) * ctm2.y_scale)); 1256 EXPECT_EQ(kSmallModeHeight + OutputConfigurator::kVerticalGap, 1257 round((kDualHeight - 1) * ctm2.y_offset)); 1258 1259 EXPECT_EQ(kSmallModeWidth - 1, round((kDualWidth - 1) * ctm1.x_scale)); 1260 EXPECT_EQ(0, round((kDualWidth - 1) * ctm1.x_offset)); 1261 1262 EXPECT_EQ(kBigModeWidth - 1, round((kDualWidth - 1) * ctm2.x_scale)); 1263 EXPECT_EQ(0, round((kDualWidth - 1) * ctm2.x_offset)); 1264} 1265 1266} // namespace chromeos 1267