Update .DEPS.git
[chromium-blink-merge.git] / chromeos / display / output_configurator_unittest.cc
blob7c74bd32b2422dfa87213eac44aa53e03172336d
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.
5 #include "chromeos/display/output_configurator.h"
7 #include <cmath>
8 #include <cstdarg>
9 #include <map>
10 #include <string>
11 #include <vector>
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"
19 namespace chromeos {
21 namespace {
23 // Strings returned by TestDelegate::GetActionsAndClear() to describe various
24 // actions that were performed.
25 const char kInitXRandR[] = "init";
26 const char kUpdateXRandR[] = "update";
27 const char kGrab[] = "grab";
28 const char kUngrab[] = "ungrab";
29 const char kSync[] = "sync";
30 const char kForceDPMS[] = "dpms";
31 const char kProjectingOn[] = "projecting";
32 const char kProjectingOff[] = "not_projecting";
34 // String returned by TestDelegate::GetActionsAndClear() if no actions were
35 // requested.
36 const char kNoActions[] = "";
38 // Returns a string describing a TestDelegate::SetBackgroundColor() call.
39 std::string GetBackgroundAction(uint32 color_argb) {
40 return base::StringPrintf("background(0x%x)", color_argb);
43 // Returns a string describing a TestDelegate::AddOutputMode() call.
44 std::string GetAddOutputModeAction(RROutput output, RRMode mode) {
45 return base::StringPrintf("add_mode(output=%lu,mode=%lu)", output, mode);
48 // Returns a string describing a TestDelegate::ConfigureCrtc() call.
49 std::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);
58 // Returns a string describing a TestDelegate::CreateFramebuffer() call.
59 std::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);
68 // Returns a string describing a TestDelegate::ConfigureCTM() call.
69 std::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);
76 // Returns a string describing a TestDelegate::SetHDCPState() call.
77 std::string GetSetHDCPStateAction(RROutput id, HDCPState state) {
78 return base::StringPrintf("set_hdcp(id=%lu,state=%d)", id, state);
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.
85 std::string JoinActions(const char* action, ...) {
86 std::string actions;
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*);
96 va_end(arg_list);
97 return actions;
100 class TestDelegate : public OutputConfigurator::Delegate {
101 public:
102 static const int kXRandREventBase = 10;
104 TestDelegate()
105 : max_configurable_pixels_(0),
106 hdcp_state_(HDCP_STATE_UNDESIRED) {}
107 virtual ~TestDelegate() {}
109 const std::vector<OutputConfigurator::OutputSnapshot>& outputs() const {
110 return outputs_;
112 void set_outputs(
113 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
114 outputs_ = outputs;
117 void set_max_configurable_pixels(int pixels) {
118 max_configurable_pixels_ = pixels;
121 void set_hdcp_state(HDCPState state) { hdcp_state_ = state; }
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;
132 const OutputConfigurator::CoordinateTransformation& get_ctm(
133 int touch_device_id) {
134 return ctms_[touch_device_id];
137 // OutputConfigurator::Delegate overrides:
138 virtual void InitXRandRExtension(int* event_base) OVERRIDE {
139 AppendAction(kInitXRandR);
140 *event_base = kXRandREventBase;
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));
150 virtual void ForceDPMSOn() OVERRIDE { AppendAction(kForceDPMS); }
151 virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs()
152 OVERRIDE {
153 return outputs_;
155 virtual void AddOutputMode(RROutput output, RRMode mode) OVERRIDE {
156 AppendAction(GetAddOutputModeAction(output, mode));
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));
165 if (max_configurable_pixels_ == 0)
166 return true;
168 OutputConfigurator::OutputSnapshot* snapshot = GetOutputFromId(output);
169 if (!snapshot)
170 return false;
172 const OutputConfigurator::ModeInfo* mode_info =
173 OutputConfigurator::GetModeInfo(*snapshot, mode);
174 if (!mode_info)
175 return false;
177 return mode_info->width * mode_info->height <= max_configurable_pixels_;
180 virtual void CreateFrameBuffer(
181 int width,
182 int height,
183 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
184 AppendAction(
185 GetFramebufferAction(width,
186 height,
187 outputs.size() >= 1 ? outputs[0].crtc : 0,
188 outputs.size() >= 2 ? outputs[1].crtc : 0));
190 virtual void ConfigureCTM(
191 int touch_device_id,
192 const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE {
193 AppendAction(GetCTMAction(touch_device_id, ctm));
194 ctms_[touch_device_id] = ctm;
196 virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE {
197 AppendAction(projecting ? kProjectingOn : kProjectingOff);
200 virtual bool GetHDCPState(RROutput id, HDCPState* state) OVERRIDE {
201 *state = hdcp_state_;
202 return true;
205 virtual bool SetHDCPState(RROutput id, HDCPState state) OVERRIDE {
206 AppendAction(GetSetHDCPStateAction(id, state));
207 return true;
210 private:
211 struct ModeDetails {
212 ModeDetails() : width(0), height(0), interlaced(false) {}
213 ModeDetails(int width, int height, bool interlaced)
214 : width(width),
215 height(height),
216 interlaced(interlaced) {}
218 int width;
219 int height;
220 bool interlaced;
223 void AppendAction(const std::string& action) {
224 if (!actions_.empty())
225 actions_ += ",";
226 actions_ += action;
229 OutputConfigurator::OutputSnapshot* GetOutputFromId(RROutput output_id) {
230 for (unsigned int i = 0; i < outputs_.size(); i++) {
231 if (outputs_[i].output == output_id)
232 return &outputs_[i];
234 return NULL;
237 std::map<RRMode, ModeDetails> modes_;
239 // Most-recently-configured transformation matrices, keyed by touch device ID.
240 std::map<int, OutputConfigurator::CoordinateTransformation> ctms_;
242 // Outputs to be returned by GetOutputs().
243 std::vector<OutputConfigurator::OutputSnapshot> outputs_;
245 std::string actions_;
247 // |max_configurable_pixels_| represents the maximum number of pixels that
248 // ConfigureCrtc will support. Tests can use this to force ConfigureCrtc
249 // to fail if attempting to set a resolution that is higher than what
250 // a device might support under a given circumstance.
251 // A value of 0 means that no limit is enforced and ConfigureCrtc will
252 // return success regardless of the resolution.
253 int max_configurable_pixels_;
255 // Result value of GetHDCPState().
256 HDCPState hdcp_state_;
258 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
261 class TestObserver : public OutputConfigurator::Observer {
262 public:
263 explicit TestObserver(OutputConfigurator* configurator)
264 : configurator_(configurator) {
265 Reset();
266 configurator_->AddObserver(this);
268 virtual ~TestObserver() {
269 configurator_->RemoveObserver(this);
272 int num_changes() const { return num_changes_; }
273 int num_failures() const { return num_failures_; }
274 const std::vector<OutputConfigurator::OutputSnapshot>& latest_outputs()
275 const {
276 return latest_outputs_;
278 OutputState latest_failed_state() const { return latest_failed_state_; }
280 void Reset() {
281 num_changes_ = 0;
282 num_failures_ = 0;
283 latest_outputs_.clear();
284 latest_failed_state_ = STATE_INVALID;
287 // OutputConfigurator::Observer overrides:
288 virtual void OnDisplayModeChanged(
289 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
290 num_changes_++;
291 latest_outputs_ = outputs;
294 virtual void OnDisplayModeChangeFailed(OutputState failed_new_state)
295 OVERRIDE {
296 num_failures_++;
297 latest_failed_state_ = failed_new_state;
300 private:
301 OutputConfigurator* configurator_; // Not owned.
303 // Number of times that OnDisplayMode*() has been called.
304 int num_changes_;
305 int num_failures_;
307 // Parameters most recently passed to OnDisplayMode*().
308 std::vector<OutputConfigurator::OutputSnapshot> latest_outputs_;
309 OutputState latest_failed_state_;
311 DISALLOW_COPY_AND_ASSIGN(TestObserver);
314 class TestStateController : public OutputConfigurator::StateController {
315 public:
316 TestStateController() : state_(STATE_DUAL_EXTENDED) {}
317 virtual ~TestStateController() {}
319 void set_state(OutputState state) { state_ = state; }
321 // OutputConfigurator::StateController overrides:
322 virtual OutputState GetStateForDisplayIds(
323 const std::vector<int64>& outputs) const OVERRIDE { return state_; }
324 virtual bool GetResolutionForDisplayId(
325 int64 display_id,
326 int *width,
327 int *height) const OVERRIDE {
328 return false;
331 private:
332 OutputState state_;
334 DISALLOW_COPY_AND_ASSIGN(TestStateController);
337 class TestMirroringController
338 : public OutputConfigurator::SoftwareMirroringController {
339 public:
340 TestMirroringController() : software_mirroring_enabled_(false) {}
341 virtual ~TestMirroringController() {}
343 virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
344 software_mirroring_enabled_ = enabled;
347 bool software_mirroring_enabled() const {
348 return software_mirroring_enabled_;
351 private:
352 bool software_mirroring_enabled_;
354 DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
357 class OutputConfiguratorTest : public testing::Test {
358 public:
359 // Predefined modes that can be used by outputs.
360 static const RRMode kSmallModeId;
361 static const int kSmallModeWidth;
362 static const int kSmallModeHeight;
364 static const RRMode kBigModeId;
365 static const int kBigModeWidth;
366 static const int kBigModeHeight;
368 OutputConfiguratorTest()
369 : observer_(&configurator_),
370 test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
371 virtual ~OutputConfiguratorTest() {}
373 virtual void SetUp() OVERRIDE {
374 delegate_ = new TestDelegate();
375 configurator_.SetDelegateForTesting(
376 scoped_ptr<OutputConfigurator::Delegate>(delegate_));
377 configurator_.set_state_controller(&state_controller_);
378 configurator_.set_mirroring_controller(&mirroring_controller_);
380 OutputConfigurator::ModeInfo small_mode_info;
381 small_mode_info.width = kSmallModeWidth;
382 small_mode_info.height = kSmallModeHeight;
384 OutputConfigurator::ModeInfo big_mode_info;
385 big_mode_info.width = kBigModeWidth;
386 big_mode_info.height = kBigModeHeight;
388 OutputConfigurator::OutputSnapshot* o = &outputs_[0];
389 o->output = 1;
390 o->crtc = 10;
391 o->current_mode = kSmallModeId;
392 o->native_mode = kSmallModeId;
393 o->type = OUTPUT_TYPE_INTERNAL;
394 o->is_aspect_preserving_scaling = true;
395 o->mode_infos[kSmallModeId] = small_mode_info;
396 o->has_display_id = true;
397 o->display_id = 123;
398 o->index = 0;
400 o = &outputs_[1];
401 o->output = 2;
402 o->crtc = 11;
403 o->current_mode = kBigModeId;
404 o->native_mode = kBigModeId;
405 o->type = OUTPUT_TYPE_HDMI;
406 o->is_aspect_preserving_scaling = true;
407 o->mode_infos[kSmallModeId] = small_mode_info;
408 o->mode_infos[kBigModeId] = big_mode_info;
409 o->has_display_id = true;
410 o->display_id = 456;
411 o->index = 1;
413 UpdateOutputs(2, false);
416 protected:
417 // Configures |delegate_| to return the first |num_outputs| entries from
418 // |outputs_|. If |send_events| is true, also sends screen-change and
419 // output-change events to |configurator_| and triggers the configure
420 // timeout if one was scheduled.
421 void UpdateOutputs(size_t num_outputs, bool send_events) {
422 ASSERT_LE(num_outputs, arraysize(outputs_));
423 std::vector<OutputConfigurator::OutputSnapshot> outputs;
424 for (size_t i = 0; i < num_outputs; ++i)
425 outputs.push_back(outputs_[i]);
426 delegate_->set_outputs(outputs);
428 if (send_events) {
429 test_api_.SendScreenChangeEvent();
430 for (size_t i = 0; i < arraysize(outputs_); ++i) {
431 const OutputConfigurator::OutputSnapshot output = outputs_[i];
432 bool connected = i < num_outputs;
433 test_api_.SendOutputChangeEvent(
434 output.output, output.crtc, output.current_mode, connected);
436 test_api_.TriggerConfigureTimeout();
440 // Initializes |configurator_| with a single internal display.
441 void InitWithSingleOutput() {
442 UpdateOutputs(1, false);
443 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
444 configurator_.Init(false);
445 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
446 configurator_.Start(0);
447 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
448 GetFramebufferAction(kSmallModeWidth,
449 kSmallModeHeight, outputs_[0].crtc, 0).c_str(),
450 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
451 outputs_[0].output).c_str(),
452 kForceDPMS, kUngrab, kProjectingOff, NULL),
453 delegate_->GetActionsAndClear());
456 base::MessageLoop message_loop_;
457 TestStateController state_controller_;
458 TestMirroringController mirroring_controller_;
459 OutputConfigurator configurator_;
460 TestObserver observer_;
461 TestDelegate* delegate_; // not owned
462 OutputConfigurator::TestApi test_api_;
464 OutputConfigurator::OutputSnapshot outputs_[2];
466 private:
467 DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
470 const RRMode OutputConfiguratorTest::kSmallModeId = 20;
471 const int OutputConfiguratorTest::kSmallModeWidth = 1366;
472 const int OutputConfiguratorTest::kSmallModeHeight = 768;
474 const RRMode OutputConfiguratorTest::kBigModeId = 21;
475 const int OutputConfiguratorTest::kBigModeWidth = 2560;
476 const int OutputConfiguratorTest::kBigModeHeight = 1600;
478 } // namespace
480 TEST_F(OutputConfiguratorTest, FindOutputModeMatchingSize) {
481 OutputConfigurator::OutputSnapshot output;
483 // Fields are width, height, interlaced, refresh rate.
484 output.mode_infos[11] = OutputConfigurator::ModeInfo(1920, 1200, false, 60.0);
485 // Different rates.
486 output.mode_infos[12] = OutputConfigurator::ModeInfo(1920, 1080, false, 30.0);
487 output.mode_infos[13] = OutputConfigurator::ModeInfo(1920, 1080, false, 50.0);
488 output.mode_infos[14] = OutputConfigurator::ModeInfo(1920, 1080, false, 40.0);
489 output.mode_infos[15] = OutputConfigurator::ModeInfo(1920, 1080, false, 0.0);
490 // Interlaced vs non-interlaced.
491 output.mode_infos[16] = OutputConfigurator::ModeInfo(1280, 720, true, 60.0);
492 output.mode_infos[17] = OutputConfigurator::ModeInfo(1280, 720, false, 40.0);
493 // Interlaced only.
494 output.mode_infos[18] = OutputConfigurator::ModeInfo(1024, 768, true, 0.0);
495 output.mode_infos[19] = OutputConfigurator::ModeInfo(1024, 768, true, 40.0);
496 output.mode_infos[20] = OutputConfigurator::ModeInfo(1024, 768, true, 60.0);
497 // Mixed.
498 output.mode_infos[21] = OutputConfigurator::ModeInfo(1024, 600, true, 60.0);
499 output.mode_infos[22] = OutputConfigurator::ModeInfo(1024, 600, false, 40.0);
500 output.mode_infos[23] = OutputConfigurator::ModeInfo(1024, 600, false, 50.0);
501 // Just one interlaced mode.
502 output.mode_infos[24] = OutputConfigurator::ModeInfo(640, 480, true, 60.0);
503 // Refresh rate not available.
504 output.mode_infos[25] = OutputConfigurator::ModeInfo(320, 200, false, 0.0);
506 EXPECT_EQ(11u, OutputConfigurator::FindOutputModeMatchingSize(output,
507 1920, 1200));
509 // Should pick highest refresh rate.
510 EXPECT_EQ(13u, OutputConfigurator::FindOutputModeMatchingSize(output,
511 1920, 1080));
513 // Should pick non-interlaced mode.
514 EXPECT_EQ(17u, OutputConfigurator::FindOutputModeMatchingSize(output,
515 1280, 720));
517 // Interlaced only. Should pick one with the highest refresh rate in
518 // interlaced mode.
519 EXPECT_EQ(20u, OutputConfigurator::FindOutputModeMatchingSize(output,
520 1024, 768));
522 // Mixed: Should pick one with the highest refresh rate in
523 // interlaced mode.
524 EXPECT_EQ(23u, OutputConfigurator::FindOutputModeMatchingSize(output,
525 1024, 600));
527 // Just one interlaced mode.
528 EXPECT_EQ(24u, OutputConfigurator::FindOutputModeMatchingSize(output,
529 640, 480));
531 // Refresh rate not available.
532 EXPECT_EQ(25u, OutputConfigurator::FindOutputModeMatchingSize(output,
533 320, 200));
535 // No mode found.
536 EXPECT_EQ(0u, OutputConfigurator::FindOutputModeMatchingSize(output,
537 1440, 900));
540 TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
541 InitWithSingleOutput();
543 // Connect a second output and check that the configurator enters
544 // extended mode.
545 observer_.Reset();
546 state_controller_.set_state(STATE_DUAL_EXTENDED);
547 UpdateOutputs(2, true);
548 const int kDualHeight =
549 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
550 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
551 GetFramebufferAction(kBigModeWidth, kDualHeight,
552 outputs_[0].crtc, outputs_[1].crtc).c_str(),
553 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
554 outputs_[0].output).c_str(),
555 GetCrtcAction(outputs_[1].crtc, 0,
556 kSmallModeHeight + OutputConfigurator::kVerticalGap,
557 kBigModeId, outputs_[1].output).c_str(),
558 kUngrab, kProjectingOn, NULL),
559 delegate_->GetActionsAndClear());
560 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
561 EXPECT_EQ(1, observer_.num_changes());
563 observer_.Reset();
564 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
565 EXPECT_EQ(JoinActions(kGrab,
566 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
567 outputs_[0].crtc, outputs_[1].crtc).c_str(),
568 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
569 outputs_[0].output).c_str(),
570 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
571 outputs_[1].output).c_str(),
572 kUngrab, NULL),
573 delegate_->GetActionsAndClear());
574 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
575 EXPECT_EQ(1, observer_.num_changes());
577 // Disconnect the second output.
578 observer_.Reset();
579 UpdateOutputs(1, true);
580 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
581 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
582 outputs_[0].crtc, 0).c_str(),
583 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
584 outputs_[0].output).c_str(),
585 kUngrab, kProjectingOff, NULL),
586 delegate_->GetActionsAndClear());
587 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
588 EXPECT_EQ(1, observer_.num_changes());
590 // Get rid of shared modes to force software mirroring.
591 outputs_[1].mode_infos.erase(kSmallModeId);
592 state_controller_.set_state(STATE_DUAL_EXTENDED);
593 UpdateOutputs(2, true);
594 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
595 GetFramebufferAction(kBigModeWidth, kDualHeight,
596 outputs_[0].crtc, outputs_[1].crtc).c_str(),
597 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
598 outputs_[0].output).c_str(),
599 GetCrtcAction(outputs_[1].crtc, 0,
600 kSmallModeHeight + OutputConfigurator::kVerticalGap,
601 kBigModeId, outputs_[1].output).c_str(),
602 kUngrab, kProjectingOn, NULL),
603 delegate_->GetActionsAndClear());
604 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
606 observer_.Reset();
607 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
608 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
609 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
610 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
611 EXPECT_EQ(1, observer_.num_changes());
613 // Setting STATE_DUAL_MIRROR should try to reconfigure.
614 observer_.Reset();
615 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
616 EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear());
617 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
618 EXPECT_EQ(1, observer_.num_changes());
620 // Set back to software mirror mode.
621 observer_.Reset();
622 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
623 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
624 delegate_->GetActionsAndClear());
625 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
626 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
627 EXPECT_EQ(1, observer_.num_changes());
629 // Disconnect the second output.
630 observer_.Reset();
631 UpdateOutputs(1, true);
632 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
633 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
634 outputs_[0].crtc, 0).c_str(),
635 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
636 outputs_[0].output).c_str(),
637 kUngrab, kProjectingOff, NULL),
638 delegate_->GetActionsAndClear());
639 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
640 EXPECT_EQ(1, observer_.num_changes());
643 TEST_F(OutputConfiguratorTest, SetDisplayPower) {
644 InitWithSingleOutput();
646 state_controller_.set_state(STATE_DUAL_MIRROR);
647 observer_.Reset();
648 UpdateOutputs(2, true);
649 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
650 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
651 outputs_[0].crtc, outputs_[1].crtc).c_str(),
652 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
653 outputs_[0].output).c_str(),
654 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
655 outputs_[1].output).c_str(),
656 kUngrab, kProjectingOn, NULL),
657 delegate_->GetActionsAndClear());
658 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
659 EXPECT_EQ(1, observer_.num_changes());
661 // Turning off the internal display should switch the external display to
662 // its native mode.
663 observer_.Reset();
664 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
665 OutputConfigurator::kSetDisplayPowerNoFlags);
666 EXPECT_EQ(JoinActions(kGrab,
667 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
668 outputs_[0].crtc, outputs_[1].crtc).c_str(),
669 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
670 outputs_[0].output).c_str(),
671 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
672 outputs_[1].output).c_str(),
673 kForceDPMS, kUngrab, NULL),
674 delegate_->GetActionsAndClear());
675 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
676 EXPECT_EQ(1, observer_.num_changes());
678 // When all displays are turned off, the framebuffer should switch back
679 // to the mirrored size.
680 observer_.Reset();
681 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
682 OutputConfigurator::kSetDisplayPowerNoFlags);
683 EXPECT_EQ(JoinActions(kGrab,
684 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
685 outputs_[0].crtc, outputs_[1].crtc).c_str(),
686 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
687 outputs_[0].output).c_str(),
688 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
689 outputs_[1].output).c_str(),
690 kUngrab, NULL),
691 delegate_->GetActionsAndClear());
692 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
693 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
694 EXPECT_EQ(1, observer_.num_changes());
696 // Turn all displays on and check that mirroring is still used.
697 observer_.Reset();
698 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
699 OutputConfigurator::kSetDisplayPowerNoFlags);
700 EXPECT_EQ(JoinActions(kGrab,
701 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
702 outputs_[0].crtc, outputs_[1].crtc).c_str(),
703 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
704 outputs_[0].output).c_str(),
705 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
706 outputs_[1].output).c_str(),
707 kForceDPMS, kUngrab, NULL),
708 delegate_->GetActionsAndClear());
709 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
710 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
711 EXPECT_EQ(1, observer_.num_changes());
713 // Get rid of shared modes to force software mirroring.
714 outputs_[1].mode_infos.erase(kSmallModeId);
715 state_controller_.set_state(STATE_DUAL_MIRROR);
716 observer_.Reset();
717 UpdateOutputs(2, true);
718 const int kDualHeight =
719 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
720 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
721 GetFramebufferAction(kBigModeWidth, kDualHeight,
722 outputs_[0].crtc, outputs_[1].crtc).c_str(),
723 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
724 outputs_[0].output).c_str(),
725 GetCrtcAction(outputs_[1].crtc, 0,
726 kSmallModeHeight + OutputConfigurator::kVerticalGap,
727 kBigModeId, outputs_[1].output).c_str(),
728 kUngrab, kProjectingOn, NULL),
729 delegate_->GetActionsAndClear());
730 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
731 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
732 EXPECT_EQ(1, observer_.num_changes());
734 // Turning off the internal display should switch the external display to
735 // its native mode.
736 observer_.Reset();
737 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
738 OutputConfigurator::kSetDisplayPowerNoFlags);
739 EXPECT_EQ(JoinActions(kGrab,
740 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
741 outputs_[0].crtc, outputs_[1].crtc).c_str(),
742 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
743 outputs_[0].output).c_str(),
744 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
745 outputs_[1].output).c_str(),
746 kForceDPMS, kUngrab, NULL),
747 delegate_->GetActionsAndClear());
748 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
749 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
750 EXPECT_EQ(1, observer_.num_changes());
752 // When all displays are turned off, the framebuffer should switch back
753 // to the extended + software mirroring.
754 observer_.Reset();
755 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
756 OutputConfigurator::kSetDisplayPowerNoFlags);
757 EXPECT_EQ(JoinActions(kGrab,
758 GetFramebufferAction(kBigModeWidth, kDualHeight,
759 outputs_[0].crtc, outputs_[1].crtc).c_str(),
760 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
761 outputs_[0].output).c_str(),
762 GetCrtcAction(outputs_[1].crtc, 0,
763 kSmallModeHeight + OutputConfigurator::kVerticalGap,
764 0, outputs_[1].output).c_str(),
765 kUngrab, NULL),
766 delegate_->GetActionsAndClear());
767 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
768 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
769 EXPECT_EQ(1, observer_.num_changes());
771 // Turn all displays on and check that mirroring is still used.
772 observer_.Reset();
773 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
774 OutputConfigurator::kSetDisplayPowerNoFlags);
775 EXPECT_EQ(JoinActions(kGrab,
776 GetFramebufferAction(kBigModeWidth, kDualHeight,
777 outputs_[0].crtc, outputs_[1].crtc).c_str(),
778 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
779 outputs_[0].output).c_str(),
780 GetCrtcAction(outputs_[1].crtc, 0,
781 kSmallModeHeight + OutputConfigurator::kVerticalGap,
782 kBigModeId, outputs_[1].output).c_str(),
783 kForceDPMS, kUngrab, NULL),
784 delegate_->GetActionsAndClear());
785 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
786 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
787 EXPECT_EQ(1, observer_.num_changes());
790 TEST_F(OutputConfiguratorTest, Casting) {
791 InitWithSingleOutput();
793 // Notify configurator that casting session is started.
794 configurator_.OnCastingSessionStartedOrStopped(true);
795 EXPECT_EQ(kProjectingOn, delegate_->GetActionsAndClear());
797 // Verify that the configurator keeps a count of active casting sessions
798 // instead of treating it as a single global state.
799 configurator_.OnCastingSessionStartedOrStopped(true);
800 EXPECT_EQ(kProjectingOn, delegate_->GetActionsAndClear());
801 configurator_.OnCastingSessionStartedOrStopped(false);
802 EXPECT_EQ(kProjectingOn, delegate_->GetActionsAndClear());
804 // Turn all displays off and check that projecting is not turned off.
805 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
806 OutputConfigurator::kSetDisplayPowerNoFlags);
807 EXPECT_EQ(JoinActions(kGrab,
808 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
809 outputs_[0].crtc, 0).c_str(),
810 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
811 outputs_[0].output).c_str(),
812 kUngrab, NULL),
813 delegate_->GetActionsAndClear());
815 // Turn all displays back on.
816 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
817 OutputConfigurator::kSetDisplayPowerNoFlags);
818 EXPECT_EQ(JoinActions(kGrab,
819 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
820 outputs_[0].crtc, 0).c_str(),
821 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
822 outputs_[0].output).c_str(),
823 kForceDPMS, kUngrab, NULL),
824 delegate_->GetActionsAndClear());
826 // Notify configurator that casting session is ended.
827 configurator_.OnCastingSessionStartedOrStopped(false);
828 EXPECT_EQ(kProjectingOff, delegate_->GetActionsAndClear());
831 TEST_F(OutputConfiguratorTest, SuspendAndResume) {
832 InitWithSingleOutput();
834 // No preparation is needed before suspending when the display is already
835 // on. The configurator should still reprobe on resume in case a display
836 // was connected while suspended.
837 configurator_.SuspendDisplays();
838 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
839 configurator_.ResumeDisplays();
840 EXPECT_EQ(JoinActions(kGrab,
841 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
842 outputs_[0].crtc, 0).c_str(),
843 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
844 outputs_[0].output).c_str(),
845 kForceDPMS, kUngrab, NULL),
846 delegate_->GetActionsAndClear());
848 // Now turn the display off before suspending and check that the
849 // configurator turns it back on and syncs with the server.
850 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
851 OutputConfigurator::kSetDisplayPowerNoFlags);
852 EXPECT_EQ(JoinActions(kGrab,
853 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
854 outputs_[0].crtc, 0).c_str(),
855 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
856 outputs_[0].output).c_str(),
857 kUngrab, NULL),
858 delegate_->GetActionsAndClear());
860 configurator_.SuspendDisplays();
861 EXPECT_EQ(JoinActions(kGrab,
862 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
863 outputs_[0].crtc, 0).c_str(),
864 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
865 outputs_[0].output).c_str(),
866 kForceDPMS, kUngrab, kSync, NULL),
867 delegate_->GetActionsAndClear());
869 configurator_.ResumeDisplays();
870 EXPECT_EQ(JoinActions(kGrab,
871 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
872 outputs_[0].crtc, 0).c_str(),
873 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
874 outputs_[0].output).c_str(),
875 kForceDPMS, kUngrab, NULL),
876 delegate_->GetActionsAndClear());
878 // If a second, external display is connected, the displays shouldn't be
879 // powered back on before suspending.
880 state_controller_.set_state(STATE_DUAL_MIRROR);
881 UpdateOutputs(2, true);
882 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
883 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
884 outputs_[0].crtc, outputs_[1].crtc).c_str(),
885 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
886 outputs_[0].output).c_str(),
887 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
888 outputs_[1].output).c_str(),
889 kUngrab, kProjectingOn, NULL),
890 delegate_->GetActionsAndClear());
892 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
893 OutputConfigurator::kSetDisplayPowerNoFlags);
894 EXPECT_EQ(JoinActions(kGrab,
895 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
896 outputs_[0].crtc, outputs_[1].crtc).c_str(),
897 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
898 outputs_[0].output).c_str(),
899 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
900 outputs_[1].output).c_str(),
901 kUngrab, NULL),
902 delegate_->GetActionsAndClear());
904 configurator_.SuspendDisplays();
905 EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
906 delegate_->GetActionsAndClear());
908 // If a display is disconnected while suspended, the configurator should
909 // pick up the change.
910 UpdateOutputs(1, false);
911 configurator_.ResumeDisplays();
912 EXPECT_EQ(JoinActions(kGrab,
913 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
914 outputs_[0].crtc, 0).c_str(),
915 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
916 outputs_[0].output).c_str(),
917 kUngrab, NULL),
918 delegate_->GetActionsAndClear());
921 TEST_F(OutputConfiguratorTest, Headless) {
922 UpdateOutputs(0, false);
923 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
924 configurator_.Init(false);
925 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
926 configurator_.Start(0);
927 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab,
928 kProjectingOff, NULL),
929 delegate_->GetActionsAndClear());
931 // Not much should happen when the display power state is changed while
932 // no displays are connected.
933 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
934 OutputConfigurator::kSetDisplayPowerNoFlags);
935 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
936 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
937 OutputConfigurator::kSetDisplayPowerNoFlags);
938 EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
939 delegate_->GetActionsAndClear());
941 // Connect an external display and check that it's configured correctly.
942 outputs_[0] = outputs_[1];
943 UpdateOutputs(1, true);
944 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
945 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
946 outputs_[0].crtc, 0).c_str(),
947 GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId,
948 outputs_[0].output).c_str(),
949 kUngrab, kProjectingOff, NULL),
950 delegate_->GetActionsAndClear());
953 TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
954 UpdateOutputs(2, false);
955 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
956 configurator_.Init(false);
957 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
959 state_controller_.set_state(STATE_DUAL_MIRROR);
960 configurator_.Start(0);
961 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
962 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
963 outputs_[0].crtc, outputs_[1].crtc).c_str(),
964 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
965 outputs_[0].output).c_str(),
966 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
967 outputs_[1].output).c_str(),
968 kForceDPMS, kUngrab, kProjectingOn, NULL),
969 delegate_->GetActionsAndClear());
972 TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
973 UpdateOutputs(0, false);
974 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
975 configurator_.Init(false);
976 configurator_.Start(0);
977 observer_.Reset();
978 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
979 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
980 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
981 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
982 EXPECT_EQ(1, observer_.num_changes());
983 EXPECT_EQ(3, observer_.num_failures());
985 UpdateOutputs(1, true);
986 observer_.Reset();
987 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
988 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
989 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
990 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
991 EXPECT_EQ(1, observer_.num_changes());
992 EXPECT_EQ(3, observer_.num_failures());
994 state_controller_.set_state(STATE_DUAL_EXTENDED);
995 UpdateOutputs(2, true);
996 observer_.Reset();
997 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
998 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
999 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
1000 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
1001 EXPECT_EQ(2, observer_.num_changes());
1002 EXPECT_EQ(2, observer_.num_failures());
1005 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithoutId) {
1006 outputs_[0].has_display_id = false;
1007 UpdateOutputs(2, false);
1008 configurator_.Init(false);
1009 state_controller_.set_state(STATE_DUAL_MIRROR);
1010 configurator_.Start(0);
1011 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
1014 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithId) {
1015 outputs_[0].has_display_id = true;
1016 UpdateOutputs(2, false);
1017 configurator_.Init(false);
1018 state_controller_.set_state(STATE_DUAL_MIRROR);
1019 configurator_.Start(0);
1020 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
1023 TEST_F(OutputConfiguratorTest, AvoidUnnecessaryProbes) {
1024 InitWithSingleOutput();
1026 // X sends several events just after the configurator starts. Check that
1027 // the output change events don't trigger an additional probe, which can
1028 // block the UI thread.
1029 test_api_.SendScreenChangeEvent();
1030 EXPECT_EQ(kUpdateXRandR, delegate_->GetActionsAndClear());
1032 test_api_.SendOutputChangeEvent(
1033 outputs_[0].output, outputs_[0].crtc, outputs_[0].current_mode, true);
1034 test_api_.SendOutputChangeEvent(
1035 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
1036 EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
1037 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1039 // Send an event stating that the second output is connected and check
1040 // that it gets updated.
1041 state_controller_.set_state(STATE_DUAL_MIRROR);
1042 UpdateOutputs(2, false);
1043 test_api_.SendOutputChangeEvent(
1044 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, true);
1045 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
1046 EXPECT_EQ(JoinActions(kGrab,
1047 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1048 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1049 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1050 outputs_[0].output).c_str(),
1051 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1052 outputs_[1].output).c_str(),
1053 kUngrab, kProjectingOn, NULL),
1054 delegate_->GetActionsAndClear());
1056 // An event about the second output changing modes should trigger another
1057 // reconfigure.
1058 test_api_.SendOutputChangeEvent(
1059 outputs_[1].output, outputs_[1].crtc, outputs_[1].native_mode, true);
1060 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
1061 EXPECT_EQ(JoinActions(kGrab,
1062 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1063 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1064 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1065 outputs_[0].output).c_str(),
1066 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1067 outputs_[1].output).c_str(),
1068 kUngrab, kProjectingOn, NULL),
1069 delegate_->GetActionsAndClear());
1071 // Disconnect the second output.
1072 UpdateOutputs(1, true);
1073 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1074 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1075 outputs_[0].crtc, 0).c_str(),
1076 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1077 outputs_[0].output).c_str(),
1078 kUngrab, kProjectingOff, NULL),
1079 delegate_->GetActionsAndClear());
1081 // An additional event about the second output being disconnected should
1082 // be ignored.
1083 test_api_.SendOutputChangeEvent(
1084 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
1085 EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
1086 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1088 // Lower the limit for which the delegate will succeed, which should result
1089 // in the second output sticking with its native mode.
1090 delegate_->set_max_configurable_pixels(1);
1091 UpdateOutputs(2, true);
1092 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1093 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1094 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1095 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1096 outputs_[0].output).c_str(),
1097 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1098 outputs_[1].output).c_str(),
1099 GetFramebufferAction(kBigModeWidth,
1100 kSmallModeHeight + kBigModeHeight +
1101 OutputConfigurator::kVerticalGap,
1102 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1103 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1104 outputs_[0].output).c_str(),
1105 GetCrtcAction(outputs_[1].crtc, 0, kSmallModeHeight +
1106 OutputConfigurator::kVerticalGap, kBigModeId,
1107 outputs_[1].output).c_str(),
1108 GetCrtcAction(outputs_[1].crtc, 0, kSmallModeHeight +
1109 OutputConfigurator::kVerticalGap, kSmallModeId,
1110 outputs_[1].output).c_str(),
1111 kUngrab, kProjectingOn, NULL),
1112 delegate_->GetActionsAndClear());
1114 // A change event reporting a mode change on the second output should
1115 // trigger another reconfigure.
1116 delegate_->set_max_configurable_pixels(0);
1117 test_api_.SendOutputChangeEvent(
1118 outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true);
1119 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
1120 EXPECT_EQ(JoinActions(kGrab,
1121 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1122 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1123 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1124 outputs_[0].output).c_str(),
1125 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1126 outputs_[1].output).c_str(),
1127 kUngrab, kProjectingOn, NULL),
1128 delegate_->GetActionsAndClear());
1131 TEST_F(OutputConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) {
1132 InitWithSingleOutput();
1133 const std::vector<OutputConfigurator::OutputSnapshot>* cached =
1134 &test_api_.cached_outputs();
1135 ASSERT_EQ(static_cast<size_t>(1), cached->size());
1136 EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode);
1138 // After connecting a second output, check that it shows up in
1139 // |cached_outputs_| even if an invalid state is requested.
1140 state_controller_.set_state(STATE_SINGLE);
1141 UpdateOutputs(2, true);
1142 cached = &test_api_.cached_outputs();
1143 ASSERT_EQ(static_cast<size_t>(2), cached->size());
1144 EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode);
1145 EXPECT_EQ(outputs_[1].current_mode, (*cached)[1].current_mode);
1148 TEST_F(OutputConfiguratorTest, PanelFitting) {
1149 // Configure the internal display to support only the big mode and the
1150 // external display to support only the small mode.
1151 outputs_[0].current_mode = kBigModeId;
1152 outputs_[0].native_mode = kBigModeId;
1153 outputs_[0].mode_infos.clear();
1154 outputs_[0].mode_infos[kBigModeId] = OutputConfigurator::ModeInfo(
1155 kBigModeWidth, kBigModeHeight, false, 60.0);
1157 outputs_[1].current_mode = kSmallModeId;
1158 outputs_[1].native_mode = kSmallModeId;
1159 outputs_[1].mode_infos.clear();
1160 outputs_[1].mode_infos[kSmallModeId] = OutputConfigurator::ModeInfo(
1161 kSmallModeWidth, kSmallModeHeight, false, 60.0);
1163 // The small mode should be added to the internal output when requesting
1164 // mirrored mode.
1165 UpdateOutputs(2, false);
1166 state_controller_.set_state(STATE_DUAL_MIRROR);
1167 configurator_.Init(true /* is_panel_fitting_enabled */);
1168 configurator_.Start(0);
1169 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
1170 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
1171 GetAddOutputModeAction(
1172 outputs_[0].output, kSmallModeId).c_str(),
1173 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1174 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1175 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1176 outputs_[0].output).c_str(),
1177 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1178 outputs_[1].output).c_str(),
1179 kForceDPMS, kUngrab, kProjectingOn, NULL),
1180 delegate_->GetActionsAndClear());
1182 // Both outputs should be using the small mode.
1183 ASSERT_EQ(1, observer_.num_changes());
1184 ASSERT_EQ(static_cast<size_t>(2), observer_.latest_outputs().size());
1185 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].mirror_mode);
1186 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].current_mode);
1187 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].mirror_mode);
1188 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].current_mode);
1190 // Also check that the newly-added small mode is present in the internal
1191 // snapshot that was passed to the observer (http://crbug.com/289159).
1192 const OutputConfigurator::ModeInfo* info = OutputConfigurator::GetModeInfo(
1193 observer_.latest_outputs()[0], kSmallModeId);
1194 ASSERT_TRUE(info);
1195 EXPECT_EQ(kSmallModeWidth, info->width);
1196 EXPECT_EQ(kSmallModeHeight, info->height);
1199 TEST_F(OutputConfiguratorTest, OutputProtection) {
1200 configurator_.Init(false);
1201 configurator_.Start(0);
1202 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1204 OutputConfigurator::OutputProtectionClientId id =
1205 configurator_.RegisterOutputProtectionClient();
1206 EXPECT_NE(0u, id);
1208 // One output.
1209 UpdateOutputs(1, true);
1210 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1211 uint32_t link_mask = 0;
1212 uint32_t protection_mask = 0;
1213 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
1214 outputs_[0].display_id,
1215 &link_mask,
1216 &protection_mask));
1217 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL), link_mask);
1218 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
1219 protection_mask);
1220 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1222 // Two outputs.
1223 UpdateOutputs(2, true);
1224 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1225 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
1226 outputs_[1].display_id,
1227 &link_mask,
1228 &protection_mask));
1229 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI),
1230 link_mask);
1231 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
1232 protection_mask);
1233 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1235 EXPECT_TRUE(
1236 configurator_.EnableOutputProtection(id,
1237 outputs_[1].display_id,
1238 OUTPUT_PROTECTION_METHOD_HDCP));
1239 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_DESIRED),
1240 delegate_->GetActionsAndClear());
1242 // Enable protection.
1243 delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
1244 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
1245 outputs_[1].display_id,
1246 &link_mask,
1247 &protection_mask));
1248 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
1249 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP),
1250 protection_mask);
1251 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1253 // Protections should be disabled after unregister.
1254 configurator_.UnregisterOutputProtectionClient(id);
1255 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_UNDESIRED),
1256 delegate_->GetActionsAndClear());
1259 TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) {
1260 OutputConfigurator::OutputProtectionClientId client1 =
1261 configurator_.RegisterOutputProtectionClient();
1262 OutputConfigurator::OutputProtectionClientId client2 =
1263 configurator_.RegisterOutputProtectionClient();
1264 EXPECT_NE(client1, client2);
1266 configurator_.Init(false);
1267 configurator_.Start(0);
1268 UpdateOutputs(2, true);
1269 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1271 // Clients never know state enableness for methods that they didn't request.
1272 EXPECT_TRUE(
1273 configurator_.EnableOutputProtection(client1,
1274 outputs_[1].display_id,
1275 OUTPUT_PROTECTION_METHOD_HDCP));
1276 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1277 HDCP_STATE_DESIRED).c_str(),
1278 delegate_->GetActionsAndClear());
1279 delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
1281 uint32_t link_mask = 0;
1282 uint32_t protection_mask = 0;
1283 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client1,
1284 outputs_[1].display_id,
1285 &link_mask,
1286 &protection_mask));
1287 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
1288 EXPECT_EQ(OUTPUT_PROTECTION_METHOD_HDCP, protection_mask);
1290 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client2,
1291 outputs_[1].display_id,
1292 &link_mask,
1293 &protection_mask));
1294 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
1295 EXPECT_EQ(OUTPUT_PROTECTION_METHOD_NONE, protection_mask);
1297 // Protections will be disabled only if no more clients request them.
1298 EXPECT_TRUE(
1299 configurator_.EnableOutputProtection(client2,
1300 outputs_[1].display_id,
1301 OUTPUT_PROTECTION_METHOD_NONE));
1302 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1303 HDCP_STATE_DESIRED).c_str(),
1304 delegate_->GetActionsAndClear());
1305 EXPECT_TRUE(
1306 configurator_.EnableOutputProtection(client1,
1307 outputs_[1].display_id,
1308 OUTPUT_PROTECTION_METHOD_NONE));
1309 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1310 HDCP_STATE_UNDESIRED).c_str(),
1311 delegate_->GetActionsAndClear());
1314 TEST_F(OutputConfiguratorTest, CTMForMultiScreens) {
1315 outputs_[0].touch_device_id = 1;
1316 outputs_[1].touch_device_id = 2;
1318 UpdateOutputs(2, false);
1319 configurator_.Init(false);
1320 state_controller_.set_state(STATE_DUAL_EXTENDED);
1321 configurator_.Start(0);
1323 const int kDualHeight =
1324 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
1325 const int kDualWidth = kBigModeWidth;
1327 OutputConfigurator::CoordinateTransformation ctm1 = delegate_->get_ctm(1);
1328 OutputConfigurator::CoordinateTransformation ctm2 = delegate_->get_ctm(2);
1330 EXPECT_EQ(kSmallModeHeight - 1, round((kDualHeight - 1) * ctm1.y_scale));
1331 EXPECT_EQ(0, round((kDualHeight - 1) * ctm1.y_offset));
1333 EXPECT_EQ(kBigModeHeight - 1, round((kDualHeight - 1) * ctm2.y_scale));
1334 EXPECT_EQ(kSmallModeHeight + OutputConfigurator::kVerticalGap,
1335 round((kDualHeight - 1) * ctm2.y_offset));
1337 EXPECT_EQ(kSmallModeWidth - 1, round((kDualWidth - 1) * ctm1.x_scale));
1338 EXPECT_EQ(0, round((kDualWidth - 1) * ctm1.x_offset));
1340 EXPECT_EQ(kBigModeWidth - 1, round((kDualWidth - 1) * ctm2.x_scale));
1341 EXPECT_EQ(0, round((kDualWidth - 1) * ctm2.x_offset));
1344 TEST_F(OutputConfiguratorTest, HandleConfigureCrtcFailure) {
1345 InitWithSingleOutput();
1347 // kFirstMode represents the first mode in the list and
1348 // also the mode that we are requesting the output_configurator
1349 // to choose. The test will be setup so that this mode will fail
1350 // and it will have to choose the next best option.
1351 const int kFirstMode = 11;
1353 // Give the mode_info lists a few reasonable modes.
1354 for (unsigned int i = 0; i < arraysize(outputs_); i++) {
1355 outputs_[i].mode_infos.clear();
1357 int current_mode = kFirstMode;
1358 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1359 2560, 1600, false, 60.0);
1360 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1361 1024, 768, false, 60.0);
1362 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1363 1280, 720, false, 60.0);
1364 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1365 1920, 1080, false, 60.0);
1366 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1367 1920, 1080, false, 40.0);
1369 outputs_[i].current_mode = kFirstMode;
1370 outputs_[i].native_mode = kFirstMode;
1373 configurator_.Init(false);
1375 // First test simply fails in STATE_SINGLE mode. This is probably
1376 // unrealistic but the want to make sure any assumptions don't
1377 // creep in.
1378 delegate_->set_max_configurable_pixels(
1379 outputs_[0].mode_infos[kFirstMode + 2].width *
1380 outputs_[0].mode_infos[kFirstMode + 2].height);
1381 state_controller_.set_state(STATE_SINGLE);
1382 UpdateOutputs(1, true);
1384 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1385 GetFramebufferAction(2560, 1600,
1386 outputs_[0].crtc, 0).c_str(),
1387 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode,
1388 outputs_[0].output).c_str(),
1389 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3,
1390 outputs_[0].output).c_str(),
1391 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 2,
1392 outputs_[0].output).c_str(),
1393 kUngrab, kProjectingOff, NULL),
1394 delegate_->GetActionsAndClear());
1396 // This test should attempt to configure a mirror mode that will not succeed
1397 // and should end up in extended mode.
1398 delegate_->set_max_configurable_pixels(
1399 outputs_[0].mode_infos[kFirstMode + 3].width *
1400 outputs_[0].mode_infos[kFirstMode + 3].height);
1401 state_controller_.set_state(STATE_DUAL_MIRROR);
1402 UpdateOutputs(2, true);
1404 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1405 GetFramebufferAction(
1406 outputs_[0].mode_infos[kFirstMode].width,
1407 outputs_[0].mode_infos[kFirstMode].height,
1408 outputs_[0].crtc,
1409 outputs_[1].crtc).c_str(),
1410 GetCrtcAction(outputs_[0].crtc,
1411 0, 0, kFirstMode, outputs_[0].output).c_str(),
1412 // First mode tried is expected to fail and it will
1413 // retry wil the 4th mode in the list.
1414 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3,
1415 outputs_[0].output).c_str(),
1416 // Then attempt to configure crtc1 with the first mode.
1417 GetCrtcAction(outputs_[1].crtc, 0, 0, kFirstMode,
1418 outputs_[1].output).c_str(),
1419 GetCrtcAction(outputs_[1].crtc, 0, 0, kFirstMode + 3,
1420 outputs_[1].output).c_str(),
1421 // Since it was requested to go into mirror mode
1422 // and the configured modes were different, it
1423 // should now try and setup a valid configurable
1424 // extended mode.
1425 GetFramebufferAction(
1426 outputs_[0].mode_infos[kFirstMode].width,
1427 outputs_[0].mode_infos[kFirstMode].height +
1428 outputs_[1].mode_infos[kFirstMode].height +
1429 OutputConfigurator::kVerticalGap,
1430 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1431 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode,
1432 outputs_[0].output).c_str(),
1433 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3,
1434 outputs_[0].output).c_str(),
1435 GetCrtcAction(outputs_[1].crtc, 0,
1436 outputs_[1].mode_infos[kFirstMode].height +
1437 OutputConfigurator::kVerticalGap, kFirstMode,
1438 outputs_[1].output).c_str(),
1439 GetCrtcAction(outputs_[1].crtc, 0,
1440 outputs_[1].mode_infos[kFirstMode].height +
1441 OutputConfigurator::kVerticalGap, kFirstMode + 3,
1442 outputs_[1].output).c_str(),
1443 kUngrab, kProjectingOn, NULL),
1444 delegate_->GetActionsAndClear());
1448 } // namespace chromeos