Getting rid of GetDefaultProfile(), clean up of ProfileManager (which was in a seriou...
[chromium-blink-merge.git] / chromeos / display / output_configurator_unittest.cc
blobc8ed8aee5317278fcf592513c94797e74ef3a301
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->is_internal = true;
394 o->type = OUTPUT_TYPE_INTERNAL;
395 o->is_aspect_preserving_scaling = true;
396 o->mode_infos[kSmallModeId] = small_mode_info;
397 o->has_display_id = true;
398 o->display_id = 123;
399 o->index = 0;
401 o = &outputs_[1];
402 o->output = 2;
403 o->crtc = 11;
404 o->current_mode = kBigModeId;
405 o->native_mode = kBigModeId;
406 o->is_internal = false;
407 o->type = OUTPUT_TYPE_HDMI;
408 o->is_aspect_preserving_scaling = true;
409 o->mode_infos[kSmallModeId] = small_mode_info;
410 o->mode_infos[kBigModeId] = big_mode_info;
411 o->has_display_id = true;
412 o->display_id = 456;
413 o->index = 1;
415 UpdateOutputs(2, false);
418 protected:
419 // Configures |delegate_| to return the first |num_outputs| entries from
420 // |outputs_|. If |send_events| is true, also sends screen-change and
421 // output-change events to |configurator_| and triggers the configure
422 // timeout if one was scheduled.
423 void UpdateOutputs(size_t num_outputs, bool send_events) {
424 ASSERT_LE(num_outputs, arraysize(outputs_));
425 std::vector<OutputConfigurator::OutputSnapshot> outputs;
426 for (size_t i = 0; i < num_outputs; ++i)
427 outputs.push_back(outputs_[i]);
428 delegate_->set_outputs(outputs);
430 if (send_events) {
431 test_api_.SendScreenChangeEvent();
432 for (size_t i = 0; i < arraysize(outputs_); ++i) {
433 const OutputConfigurator::OutputSnapshot output = outputs_[i];
434 bool connected = i < num_outputs;
435 test_api_.SendOutputChangeEvent(
436 output.output, output.crtc, output.current_mode, connected);
438 test_api_.TriggerConfigureTimeout();
442 // Initializes |configurator_| with a single internal display.
443 void InitWithSingleOutput() {
444 UpdateOutputs(1, false);
445 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
446 configurator_.Init(false);
447 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
448 configurator_.Start(0);
449 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
450 GetFramebufferAction(kSmallModeWidth,
451 kSmallModeHeight, outputs_[0].crtc, 0).c_str(),
452 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
453 outputs_[0].output).c_str(),
454 kForceDPMS, kUngrab, kProjectingOff, NULL),
455 delegate_->GetActionsAndClear());
458 base::MessageLoop message_loop_;
459 TestStateController state_controller_;
460 TestMirroringController mirroring_controller_;
461 OutputConfigurator configurator_;
462 TestObserver observer_;
463 TestDelegate* delegate_; // not owned
464 OutputConfigurator::TestApi test_api_;
466 OutputConfigurator::OutputSnapshot outputs_[2];
468 private:
469 DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
472 const RRMode OutputConfiguratorTest::kSmallModeId = 20;
473 const int OutputConfiguratorTest::kSmallModeWidth = 1366;
474 const int OutputConfiguratorTest::kSmallModeHeight = 768;
476 const RRMode OutputConfiguratorTest::kBigModeId = 21;
477 const int OutputConfiguratorTest::kBigModeWidth = 2560;
478 const int OutputConfiguratorTest::kBigModeHeight = 1600;
480 } // namespace
482 TEST_F(OutputConfiguratorTest, FindOutputModeMatchingSize) {
483 OutputConfigurator::OutputSnapshot output;
485 // Fields are width, height, interlaced, refresh rate.
486 output.mode_infos[11] = OutputConfigurator::ModeInfo(1920, 1200, false, 60.0);
487 // Different rates.
488 output.mode_infos[12] = OutputConfigurator::ModeInfo(1920, 1080, false, 30.0);
489 output.mode_infos[13] = OutputConfigurator::ModeInfo(1920, 1080, false, 50.0);
490 output.mode_infos[14] = OutputConfigurator::ModeInfo(1920, 1080, false, 40.0);
491 output.mode_infos[15] = OutputConfigurator::ModeInfo(1920, 1080, false, 0.0);
492 // Interlaced vs non-interlaced.
493 output.mode_infos[16] = OutputConfigurator::ModeInfo(1280, 720, true, 60.0);
494 output.mode_infos[17] = OutputConfigurator::ModeInfo(1280, 720, false, 40.0);
495 // Interlaced only.
496 output.mode_infos[18] = OutputConfigurator::ModeInfo(1024, 768, true, 0.0);
497 output.mode_infos[19] = OutputConfigurator::ModeInfo(1024, 768, true, 40.0);
498 output.mode_infos[20] = OutputConfigurator::ModeInfo(1024, 768, true, 60.0);
499 // Mixed.
500 output.mode_infos[21] = OutputConfigurator::ModeInfo(1024, 600, true, 60.0);
501 output.mode_infos[22] = OutputConfigurator::ModeInfo(1024, 600, false, 40.0);
502 output.mode_infos[23] = OutputConfigurator::ModeInfo(1024, 600, false, 50.0);
503 // Just one interlaced mode.
504 output.mode_infos[24] = OutputConfigurator::ModeInfo(640, 480, true, 60.0);
505 // Refresh rate not available.
506 output.mode_infos[25] = OutputConfigurator::ModeInfo(320, 200, false, 0.0);
508 EXPECT_EQ(11u, OutputConfigurator::FindOutputModeMatchingSize(output,
509 1920, 1200));
511 // Should pick highest refresh rate.
512 EXPECT_EQ(13u, OutputConfigurator::FindOutputModeMatchingSize(output,
513 1920, 1080));
515 // Should pick non-interlaced mode.
516 EXPECT_EQ(17u, OutputConfigurator::FindOutputModeMatchingSize(output,
517 1280, 720));
519 // Interlaced only. Should pick one with the highest refresh rate in
520 // interlaced mode.
521 EXPECT_EQ(20u, OutputConfigurator::FindOutputModeMatchingSize(output,
522 1024, 768));
524 // Mixed: Should pick one with the highest refresh rate in
525 // interlaced mode.
526 EXPECT_EQ(23u, OutputConfigurator::FindOutputModeMatchingSize(output,
527 1024, 600));
529 // Just one interlaced mode.
530 EXPECT_EQ(24u, OutputConfigurator::FindOutputModeMatchingSize(output,
531 640, 480));
533 // Refresh rate not available.
534 EXPECT_EQ(25u, OutputConfigurator::FindOutputModeMatchingSize(output,
535 320, 200));
537 // No mode found.
538 EXPECT_EQ(0u, OutputConfigurator::FindOutputModeMatchingSize(output,
539 1440, 900));
542 TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
543 InitWithSingleOutput();
545 // Connect a second output and check that the configurator enters
546 // extended mode.
547 observer_.Reset();
548 state_controller_.set_state(STATE_DUAL_EXTENDED);
549 UpdateOutputs(2, true);
550 const int kDualHeight =
551 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
552 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
553 GetFramebufferAction(kBigModeWidth, kDualHeight,
554 outputs_[0].crtc, outputs_[1].crtc).c_str(),
555 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
556 outputs_[0].output).c_str(),
557 GetCrtcAction(outputs_[1].crtc, 0,
558 kSmallModeHeight + OutputConfigurator::kVerticalGap,
559 kBigModeId, outputs_[1].output).c_str(),
560 kUngrab, kProjectingOn, NULL),
561 delegate_->GetActionsAndClear());
562 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
563 EXPECT_EQ(1, observer_.num_changes());
565 observer_.Reset();
566 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
567 EXPECT_EQ(JoinActions(kGrab,
568 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
569 outputs_[0].crtc, outputs_[1].crtc).c_str(),
570 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
571 outputs_[0].output).c_str(),
572 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
573 outputs_[1].output).c_str(),
574 kUngrab, NULL),
575 delegate_->GetActionsAndClear());
576 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
577 EXPECT_EQ(1, observer_.num_changes());
579 // Disconnect the second output.
580 observer_.Reset();
581 UpdateOutputs(1, true);
582 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
583 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
584 outputs_[0].crtc, 0).c_str(),
585 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
586 outputs_[0].output).c_str(),
587 kUngrab, kProjectingOff, NULL),
588 delegate_->GetActionsAndClear());
589 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
590 EXPECT_EQ(1, observer_.num_changes());
592 // Get rid of shared modes to force software mirroring.
593 outputs_[1].mode_infos.erase(kSmallModeId);
594 state_controller_.set_state(STATE_DUAL_EXTENDED);
595 UpdateOutputs(2, true);
596 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
597 GetFramebufferAction(kBigModeWidth, kDualHeight,
598 outputs_[0].crtc, outputs_[1].crtc).c_str(),
599 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
600 outputs_[0].output).c_str(),
601 GetCrtcAction(outputs_[1].crtc, 0,
602 kSmallModeHeight + OutputConfigurator::kVerticalGap,
603 kBigModeId, outputs_[1].output).c_str(),
604 kUngrab, kProjectingOn, NULL),
605 delegate_->GetActionsAndClear());
606 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
608 observer_.Reset();
609 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
610 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
611 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
612 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
613 EXPECT_EQ(1, observer_.num_changes());
615 // Setting STATE_DUAL_MIRROR should try to reconfigure.
616 observer_.Reset();
617 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
618 EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear());
619 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
620 EXPECT_EQ(1, observer_.num_changes());
622 // Set back to software mirror mode.
623 observer_.Reset();
624 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
625 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
626 delegate_->GetActionsAndClear());
627 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
628 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
629 EXPECT_EQ(1, observer_.num_changes());
631 // Disconnect the second output.
632 observer_.Reset();
633 UpdateOutputs(1, true);
634 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
635 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
636 outputs_[0].crtc, 0).c_str(),
637 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
638 outputs_[0].output).c_str(),
639 kUngrab, kProjectingOff, NULL),
640 delegate_->GetActionsAndClear());
641 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
642 EXPECT_EQ(1, observer_.num_changes());
645 TEST_F(OutputConfiguratorTest, SetDisplayPower) {
646 InitWithSingleOutput();
648 state_controller_.set_state(STATE_DUAL_MIRROR);
649 observer_.Reset();
650 UpdateOutputs(2, true);
651 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
652 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
653 outputs_[0].crtc, outputs_[1].crtc).c_str(),
654 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
655 outputs_[0].output).c_str(),
656 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
657 outputs_[1].output).c_str(),
658 kUngrab, kProjectingOn, NULL),
659 delegate_->GetActionsAndClear());
660 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
661 EXPECT_EQ(1, observer_.num_changes());
663 // Turning off the internal display should switch the external display to
664 // its native mode.
665 observer_.Reset();
666 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
667 OutputConfigurator::kSetDisplayPowerNoFlags);
668 EXPECT_EQ(JoinActions(kGrab,
669 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
670 outputs_[0].crtc, outputs_[1].crtc).c_str(),
671 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
672 outputs_[0].output).c_str(),
673 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
674 outputs_[1].output).c_str(),
675 kForceDPMS, kUngrab, NULL),
676 delegate_->GetActionsAndClear());
677 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
678 EXPECT_EQ(1, observer_.num_changes());
680 // When all displays are turned off, the framebuffer should switch back
681 // to the mirrored size.
682 observer_.Reset();
683 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
684 OutputConfigurator::kSetDisplayPowerNoFlags);
685 EXPECT_EQ(JoinActions(kGrab,
686 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
687 outputs_[0].crtc, outputs_[1].crtc).c_str(),
688 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
689 outputs_[0].output).c_str(),
690 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
691 outputs_[1].output).c_str(),
692 kUngrab, NULL),
693 delegate_->GetActionsAndClear());
694 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
695 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
696 EXPECT_EQ(1, observer_.num_changes());
698 // Turn all displays on and check that mirroring is still used.
699 observer_.Reset();
700 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
701 OutputConfigurator::kSetDisplayPowerNoFlags);
702 EXPECT_EQ(JoinActions(kGrab,
703 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
704 outputs_[0].crtc, outputs_[1].crtc).c_str(),
705 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
706 outputs_[0].output).c_str(),
707 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
708 outputs_[1].output).c_str(),
709 kForceDPMS, kUngrab, NULL),
710 delegate_->GetActionsAndClear());
711 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
712 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
713 EXPECT_EQ(1, observer_.num_changes());
715 // Get rid of shared modes to force software mirroring.
716 outputs_[1].mode_infos.erase(kSmallModeId);
717 state_controller_.set_state(STATE_DUAL_MIRROR);
718 observer_.Reset();
719 UpdateOutputs(2, true);
720 const int kDualHeight =
721 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
722 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
723 GetFramebufferAction(kBigModeWidth, kDualHeight,
724 outputs_[0].crtc, outputs_[1].crtc).c_str(),
725 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
726 outputs_[0].output).c_str(),
727 GetCrtcAction(outputs_[1].crtc, 0,
728 kSmallModeHeight + OutputConfigurator::kVerticalGap,
729 kBigModeId, outputs_[1].output).c_str(),
730 kUngrab, kProjectingOn, NULL),
731 delegate_->GetActionsAndClear());
732 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
733 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
734 EXPECT_EQ(1, observer_.num_changes());
736 // Turning off the internal display should switch the external display to
737 // its native mode.
738 observer_.Reset();
739 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
740 OutputConfigurator::kSetDisplayPowerNoFlags);
741 EXPECT_EQ(JoinActions(kGrab,
742 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
743 outputs_[0].crtc, outputs_[1].crtc).c_str(),
744 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
745 outputs_[0].output).c_str(),
746 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
747 outputs_[1].output).c_str(),
748 kForceDPMS, kUngrab, NULL),
749 delegate_->GetActionsAndClear());
750 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
751 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
752 EXPECT_EQ(1, observer_.num_changes());
754 // When all displays are turned off, the framebuffer should switch back
755 // to the extended + software mirroring.
756 observer_.Reset();
757 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
758 OutputConfigurator::kSetDisplayPowerNoFlags);
759 EXPECT_EQ(JoinActions(kGrab,
760 GetFramebufferAction(kBigModeWidth, kDualHeight,
761 outputs_[0].crtc, outputs_[1].crtc).c_str(),
762 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
763 outputs_[0].output).c_str(),
764 GetCrtcAction(outputs_[1].crtc, 0,
765 kSmallModeHeight + OutputConfigurator::kVerticalGap,
766 0, outputs_[1].output).c_str(),
767 kUngrab, NULL),
768 delegate_->GetActionsAndClear());
769 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
770 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
771 EXPECT_EQ(1, observer_.num_changes());
773 // Turn all displays on and check that mirroring is still used.
774 observer_.Reset();
775 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
776 OutputConfigurator::kSetDisplayPowerNoFlags);
777 EXPECT_EQ(JoinActions(kGrab,
778 GetFramebufferAction(kBigModeWidth, kDualHeight,
779 outputs_[0].crtc, outputs_[1].crtc).c_str(),
780 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
781 outputs_[0].output).c_str(),
782 GetCrtcAction(outputs_[1].crtc, 0,
783 kSmallModeHeight + OutputConfigurator::kVerticalGap,
784 kBigModeId, outputs_[1].output).c_str(),
785 kForceDPMS, kUngrab, NULL),
786 delegate_->GetActionsAndClear());
787 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
788 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
789 EXPECT_EQ(1, observer_.num_changes());
792 TEST_F(OutputConfiguratorTest, SuspendAndResume) {
793 InitWithSingleOutput();
795 // No preparation is needed before suspending when the display is already
796 // on. The configurator should still reprobe on resume in case a display
797 // was connected while suspended.
798 configurator_.SuspendDisplays();
799 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
800 configurator_.ResumeDisplays();
801 EXPECT_EQ(JoinActions(kGrab,
802 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
803 outputs_[0].crtc, 0).c_str(),
804 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
805 outputs_[0].output).c_str(),
806 kForceDPMS, kUngrab, NULL),
807 delegate_->GetActionsAndClear());
809 // Now turn the display off before suspending and check that the
810 // configurator turns it back on and syncs with the server.
811 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
812 OutputConfigurator::kSetDisplayPowerNoFlags);
813 EXPECT_EQ(JoinActions(kGrab,
814 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
815 outputs_[0].crtc, 0).c_str(),
816 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
817 outputs_[0].output).c_str(),
818 kUngrab, NULL),
819 delegate_->GetActionsAndClear());
821 configurator_.SuspendDisplays();
822 EXPECT_EQ(JoinActions(kGrab,
823 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
824 outputs_[0].crtc, 0).c_str(),
825 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
826 outputs_[0].output).c_str(),
827 kForceDPMS, kUngrab, kSync, NULL),
828 delegate_->GetActionsAndClear());
830 configurator_.ResumeDisplays();
831 EXPECT_EQ(JoinActions(kGrab,
832 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
833 outputs_[0].crtc, 0).c_str(),
834 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
835 outputs_[0].output).c_str(),
836 kForceDPMS, kUngrab, NULL),
837 delegate_->GetActionsAndClear());
839 // If a second, external display is connected, the displays shouldn't be
840 // powered back on before suspending.
841 state_controller_.set_state(STATE_DUAL_MIRROR);
842 UpdateOutputs(2, true);
843 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
844 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
845 outputs_[0].crtc, outputs_[1].crtc).c_str(),
846 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
847 outputs_[0].output).c_str(),
848 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
849 outputs_[1].output).c_str(),
850 kUngrab, kProjectingOn, NULL),
851 delegate_->GetActionsAndClear());
853 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
854 OutputConfigurator::kSetDisplayPowerNoFlags);
855 EXPECT_EQ(JoinActions(kGrab,
856 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
857 outputs_[0].crtc, outputs_[1].crtc).c_str(),
858 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
859 outputs_[0].output).c_str(),
860 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
861 outputs_[1].output).c_str(),
862 kUngrab, NULL),
863 delegate_->GetActionsAndClear());
865 configurator_.SuspendDisplays();
866 EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
867 delegate_->GetActionsAndClear());
869 // If a display is disconnected while suspended, the configurator should
870 // pick up the change.
871 UpdateOutputs(1, false);
872 configurator_.ResumeDisplays();
873 EXPECT_EQ(JoinActions(kGrab,
874 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
875 outputs_[0].crtc, 0).c_str(),
876 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
877 outputs_[0].output).c_str(),
878 kUngrab, NULL),
879 delegate_->GetActionsAndClear());
882 TEST_F(OutputConfiguratorTest, Headless) {
883 UpdateOutputs(0, false);
884 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
885 configurator_.Init(false);
886 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
887 configurator_.Start(0);
888 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab,
889 kProjectingOff, NULL),
890 delegate_->GetActionsAndClear());
892 // Not much should happen when the display power state is changed while
893 // no displays are connected.
894 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
895 OutputConfigurator::kSetDisplayPowerNoFlags);
896 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
897 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
898 OutputConfigurator::kSetDisplayPowerNoFlags);
899 EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
900 delegate_->GetActionsAndClear());
902 // Connect an external display and check that it's configured correctly.
903 outputs_[0] = outputs_[1];
904 UpdateOutputs(1, true);
905 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
906 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
907 outputs_[0].crtc, 0).c_str(),
908 GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId,
909 outputs_[0].output).c_str(),
910 kUngrab, kProjectingOff, NULL),
911 delegate_->GetActionsAndClear());
914 TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
915 UpdateOutputs(2, false);
916 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
917 configurator_.Init(false);
918 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
920 state_controller_.set_state(STATE_DUAL_MIRROR);
921 configurator_.Start(0);
922 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
923 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
924 outputs_[0].crtc, outputs_[1].crtc).c_str(),
925 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
926 outputs_[0].output).c_str(),
927 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
928 outputs_[1].output).c_str(),
929 kForceDPMS, kUngrab, kProjectingOn, NULL),
930 delegate_->GetActionsAndClear());
933 TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
934 UpdateOutputs(0, false);
935 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
936 configurator_.Init(false);
937 configurator_.Start(0);
938 observer_.Reset();
939 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
940 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
941 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
942 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
943 EXPECT_EQ(1, observer_.num_changes());
944 EXPECT_EQ(3, observer_.num_failures());
946 UpdateOutputs(1, true);
947 observer_.Reset();
948 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
949 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
950 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
951 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
952 EXPECT_EQ(1, observer_.num_changes());
953 EXPECT_EQ(3, observer_.num_failures());
955 state_controller_.set_state(STATE_DUAL_EXTENDED);
956 UpdateOutputs(2, true);
957 observer_.Reset();
958 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
959 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
960 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
961 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
962 EXPECT_EQ(2, observer_.num_changes());
963 EXPECT_EQ(2, observer_.num_failures());
966 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithoutId) {
967 outputs_[0].has_display_id = false;
968 UpdateOutputs(2, false);
969 configurator_.Init(false);
970 state_controller_.set_state(STATE_DUAL_MIRROR);
971 configurator_.Start(0);
972 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
975 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithId) {
976 outputs_[0].has_display_id = true;
977 UpdateOutputs(2, false);
978 configurator_.Init(false);
979 state_controller_.set_state(STATE_DUAL_MIRROR);
980 configurator_.Start(0);
981 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
984 TEST_F(OutputConfiguratorTest, AvoidUnnecessaryProbes) {
985 InitWithSingleOutput();
987 // X sends several events just after the configurator starts. Check that
988 // the output change events don't trigger an additional probe, which can
989 // block the UI thread.
990 test_api_.SendScreenChangeEvent();
991 EXPECT_EQ(kUpdateXRandR, delegate_->GetActionsAndClear());
993 test_api_.SendOutputChangeEvent(
994 outputs_[0].output, outputs_[0].crtc, outputs_[0].current_mode, true);
995 test_api_.SendOutputChangeEvent(
996 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
997 EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
998 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1000 // Send an event stating that the second output is connected and check
1001 // that it gets updated.
1002 state_controller_.set_state(STATE_DUAL_MIRROR);
1003 UpdateOutputs(2, false);
1004 test_api_.SendOutputChangeEvent(
1005 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, true);
1006 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
1007 EXPECT_EQ(JoinActions(kGrab,
1008 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1009 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1010 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1011 outputs_[0].output).c_str(),
1012 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1013 outputs_[1].output).c_str(),
1014 kUngrab, kProjectingOn, NULL),
1015 delegate_->GetActionsAndClear());
1017 // An event about the second output changing modes should trigger another
1018 // reconfigure.
1019 test_api_.SendOutputChangeEvent(
1020 outputs_[1].output, outputs_[1].crtc, outputs_[1].native_mode, true);
1021 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
1022 EXPECT_EQ(JoinActions(kGrab,
1023 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1024 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1025 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1026 outputs_[0].output).c_str(),
1027 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1028 outputs_[1].output).c_str(),
1029 kUngrab, kProjectingOn, NULL),
1030 delegate_->GetActionsAndClear());
1032 // Disconnect the second output.
1033 UpdateOutputs(1, true);
1034 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1035 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1036 outputs_[0].crtc, 0).c_str(),
1037 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1038 outputs_[0].output).c_str(),
1039 kUngrab, kProjectingOff, NULL),
1040 delegate_->GetActionsAndClear());
1042 // An additional event about the second output being disconnected should
1043 // be ignored.
1044 test_api_.SendOutputChangeEvent(
1045 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
1046 EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
1047 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1049 // Lower the limit for which the delegate will succeed, which should result
1050 // in the second output sticking with its native mode.
1051 delegate_->set_max_configurable_pixels(1);
1052 UpdateOutputs(2, true);
1053 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1054 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1055 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1056 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1057 outputs_[0].output).c_str(),
1058 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1059 outputs_[1].output).c_str(),
1060 GetFramebufferAction(kBigModeWidth,
1061 kSmallModeHeight + kBigModeHeight +
1062 OutputConfigurator::kVerticalGap,
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, kSmallModeHeight +
1067 OutputConfigurator::kVerticalGap, kBigModeId,
1068 outputs_[1].output).c_str(),
1069 GetCrtcAction(outputs_[1].crtc, 0, kSmallModeHeight +
1070 OutputConfigurator::kVerticalGap, kSmallModeId,
1071 outputs_[1].output).c_str(),
1072 kUngrab, kProjectingOn, NULL),
1073 delegate_->GetActionsAndClear());
1075 // A change event reporting a mode change on the second output should
1076 // trigger another reconfigure.
1077 delegate_->set_max_configurable_pixels(0);
1078 test_api_.SendOutputChangeEvent(
1079 outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true);
1080 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
1081 EXPECT_EQ(JoinActions(kGrab,
1082 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1083 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1084 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1085 outputs_[0].output).c_str(),
1086 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1087 outputs_[1].output).c_str(),
1088 kUngrab, kProjectingOn, NULL),
1089 delegate_->GetActionsAndClear());
1092 TEST_F(OutputConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) {
1093 InitWithSingleOutput();
1094 const std::vector<OutputConfigurator::OutputSnapshot>* cached =
1095 &test_api_.cached_outputs();
1096 ASSERT_EQ(static_cast<size_t>(1), cached->size());
1097 EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode);
1099 // After connecting a second output, check that it shows up in
1100 // |cached_outputs_| even if an invalid state is requested.
1101 state_controller_.set_state(STATE_SINGLE);
1102 UpdateOutputs(2, true);
1103 cached = &test_api_.cached_outputs();
1104 ASSERT_EQ(static_cast<size_t>(2), cached->size());
1105 EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode);
1106 EXPECT_EQ(outputs_[1].current_mode, (*cached)[1].current_mode);
1109 TEST_F(OutputConfiguratorTest, PanelFitting) {
1110 // Configure the internal display to support only the big mode and the
1111 // external display to support only the small mode.
1112 outputs_[0].current_mode = kBigModeId;
1113 outputs_[0].native_mode = kBigModeId;
1114 outputs_[0].mode_infos.clear();
1115 outputs_[0].mode_infos[kBigModeId] = OutputConfigurator::ModeInfo(
1116 kBigModeWidth, kBigModeHeight, false, 60.0);
1118 outputs_[1].current_mode = kSmallModeId;
1119 outputs_[1].native_mode = kSmallModeId;
1120 outputs_[1].mode_infos.clear();
1121 outputs_[1].mode_infos[kSmallModeId] = OutputConfigurator::ModeInfo(
1122 kSmallModeWidth, kSmallModeHeight, false, 60.0);
1124 // The small mode should be added to the internal output when requesting
1125 // mirrored mode.
1126 UpdateOutputs(2, false);
1127 state_controller_.set_state(STATE_DUAL_MIRROR);
1128 configurator_.Init(true /* is_panel_fitting_enabled */);
1129 configurator_.Start(0);
1130 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
1131 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
1132 GetAddOutputModeAction(
1133 outputs_[0].output, kSmallModeId).c_str(),
1134 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1135 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1136 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1137 outputs_[0].output).c_str(),
1138 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1139 outputs_[1].output).c_str(),
1140 kForceDPMS, kUngrab, kProjectingOn, NULL),
1141 delegate_->GetActionsAndClear());
1143 // Both outputs should be using the small mode.
1144 ASSERT_EQ(1, observer_.num_changes());
1145 ASSERT_EQ(static_cast<size_t>(2), observer_.latest_outputs().size());
1146 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].mirror_mode);
1147 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].current_mode);
1148 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].mirror_mode);
1149 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].current_mode);
1151 // Also check that the newly-added small mode is present in the internal
1152 // snapshot that was passed to the observer (http://crbug.com/289159).
1153 const OutputConfigurator::ModeInfo* info = OutputConfigurator::GetModeInfo(
1154 observer_.latest_outputs()[0], kSmallModeId);
1155 ASSERT_TRUE(info);
1156 EXPECT_EQ(kSmallModeWidth, info->width);
1157 EXPECT_EQ(kSmallModeHeight, info->height);
1160 TEST_F(OutputConfiguratorTest, OutputProtection) {
1161 configurator_.Init(false);
1162 configurator_.Start(0);
1163 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1165 OutputConfigurator::OutputProtectionClientId id =
1166 configurator_.RegisterOutputProtectionClient();
1167 EXPECT_NE(0u, id);
1169 // One output.
1170 UpdateOutputs(1, true);
1171 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1172 uint32_t link_mask = 0;
1173 uint32_t protection_mask = 0;
1174 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
1175 outputs_[0].display_id,
1176 &link_mask,
1177 &protection_mask));
1178 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL), link_mask);
1179 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
1180 protection_mask);
1181 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1183 // Two outputs.
1184 UpdateOutputs(2, true);
1185 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1186 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
1187 outputs_[1].display_id,
1188 &link_mask,
1189 &protection_mask));
1190 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI),
1191 link_mask);
1192 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
1193 protection_mask);
1194 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1196 EXPECT_TRUE(
1197 configurator_.EnableOutputProtection(id,
1198 outputs_[1].display_id,
1199 OUTPUT_PROTECTION_METHOD_HDCP));
1200 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_DESIRED),
1201 delegate_->GetActionsAndClear());
1203 // Enable protection.
1204 delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
1205 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
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(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP),
1211 protection_mask);
1212 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1214 // Protections should be disabled after unregister.
1215 configurator_.UnregisterOutputProtectionClient(id);
1216 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_UNDESIRED),
1217 delegate_->GetActionsAndClear());
1220 TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) {
1221 OutputConfigurator::OutputProtectionClientId client1 =
1222 configurator_.RegisterOutputProtectionClient();
1223 OutputConfigurator::OutputProtectionClientId client2 =
1224 configurator_.RegisterOutputProtectionClient();
1225 EXPECT_NE(client1, client2);
1227 configurator_.Init(false);
1228 configurator_.Start(0);
1229 UpdateOutputs(2, true);
1230 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1232 // Clients never know state enableness for methods that they didn't request.
1233 EXPECT_TRUE(
1234 configurator_.EnableOutputProtection(client1,
1235 outputs_[1].display_id,
1236 OUTPUT_PROTECTION_METHOD_HDCP));
1237 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1238 HDCP_STATE_DESIRED).c_str(),
1239 delegate_->GetActionsAndClear());
1240 delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
1242 uint32_t link_mask = 0;
1243 uint32_t protection_mask = 0;
1244 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client1,
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(OUTPUT_PROTECTION_METHOD_HDCP, protection_mask);
1251 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client2,
1252 outputs_[1].display_id,
1253 &link_mask,
1254 &protection_mask));
1255 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
1256 EXPECT_EQ(OUTPUT_PROTECTION_METHOD_NONE, protection_mask);
1258 // Protections will be disabled only if no more clients request them.
1259 EXPECT_TRUE(
1260 configurator_.EnableOutputProtection(client2,
1261 outputs_[1].display_id,
1262 OUTPUT_PROTECTION_METHOD_NONE));
1263 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1264 HDCP_STATE_DESIRED).c_str(),
1265 delegate_->GetActionsAndClear());
1266 EXPECT_TRUE(
1267 configurator_.EnableOutputProtection(client1,
1268 outputs_[1].display_id,
1269 OUTPUT_PROTECTION_METHOD_NONE));
1270 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1271 HDCP_STATE_UNDESIRED).c_str(),
1272 delegate_->GetActionsAndClear());
1275 TEST_F(OutputConfiguratorTest, CTMForMultiScreens) {
1276 outputs_[0].touch_device_id = 1;
1277 outputs_[1].touch_device_id = 2;
1279 UpdateOutputs(2, false);
1280 configurator_.Init(false);
1281 state_controller_.set_state(STATE_DUAL_EXTENDED);
1282 configurator_.Start(0);
1284 const int kDualHeight =
1285 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
1286 const int kDualWidth = kBigModeWidth;
1288 OutputConfigurator::CoordinateTransformation ctm1 = delegate_->get_ctm(1);
1289 OutputConfigurator::CoordinateTransformation ctm2 = delegate_->get_ctm(2);
1291 EXPECT_EQ(kSmallModeHeight - 1, round((kDualHeight - 1) * ctm1.y_scale));
1292 EXPECT_EQ(0, round((kDualHeight - 1) * ctm1.y_offset));
1294 EXPECT_EQ(kBigModeHeight - 1, round((kDualHeight - 1) * ctm2.y_scale));
1295 EXPECT_EQ(kSmallModeHeight + OutputConfigurator::kVerticalGap,
1296 round((kDualHeight - 1) * ctm2.y_offset));
1298 EXPECT_EQ(kSmallModeWidth - 1, round((kDualWidth - 1) * ctm1.x_scale));
1299 EXPECT_EQ(0, round((kDualWidth - 1) * ctm1.x_offset));
1301 EXPECT_EQ(kBigModeWidth - 1, round((kDualWidth - 1) * ctm2.x_scale));
1302 EXPECT_EQ(0, round((kDualWidth - 1) * ctm2.x_offset));
1305 TEST_F(OutputConfiguratorTest, HandleConfigureCrtcFailure) {
1306 InitWithSingleOutput();
1308 // kFirstMode represents the first mode in the list and
1309 // also the mode that we are requesting the output_configurator
1310 // to choose. The test will be setup so that this mode will fail
1311 // and it will have to choose the next best option.
1312 const int kFirstMode = 11;
1314 // Give the mode_info lists a few reasonable modes.
1315 for (unsigned int i = 0; i < arraysize(outputs_); i++) {
1316 outputs_[i].mode_infos.clear();
1318 int current_mode = kFirstMode;
1319 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1320 2560, 1600, false, 60.0);
1321 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1322 1024, 768, false, 60.0);
1323 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1324 1280, 720, false, 60.0);
1325 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1326 1920, 1080, false, 60.0);
1327 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo(
1328 1920, 1080, false, 40.0);
1330 outputs_[i].current_mode = kFirstMode;
1331 outputs_[i].native_mode = kFirstMode;
1334 configurator_.Init(false);
1336 // First test simply fails in STATE_SINGLE mode. This is probably
1337 // unrealistic but the want to make sure any assumptions don't
1338 // creep in.
1339 delegate_->set_max_configurable_pixels(
1340 outputs_[0].mode_infos[kFirstMode + 2].width *
1341 outputs_[0].mode_infos[kFirstMode + 2].height);
1342 state_controller_.set_state(STATE_SINGLE);
1343 UpdateOutputs(1, true);
1345 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1346 GetFramebufferAction(2560, 1600,
1347 outputs_[0].crtc, 0).c_str(),
1348 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode,
1349 outputs_[0].output).c_str(),
1350 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3,
1351 outputs_[0].output).c_str(),
1352 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 2,
1353 outputs_[0].output).c_str(),
1354 kUngrab, kProjectingOff, NULL),
1355 delegate_->GetActionsAndClear());
1357 // This test should attempt to configure a mirror mode that will not succeed
1358 // and should end up in extended mode.
1359 delegate_->set_max_configurable_pixels(
1360 outputs_[0].mode_infos[kFirstMode + 3].width *
1361 outputs_[0].mode_infos[kFirstMode + 3].height);
1362 state_controller_.set_state(STATE_DUAL_MIRROR);
1363 UpdateOutputs(2, true);
1365 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1366 GetFramebufferAction(
1367 outputs_[0].mode_infos[kFirstMode].width,
1368 outputs_[0].mode_infos[kFirstMode].height,
1369 outputs_[0].crtc,
1370 outputs_[1].crtc).c_str(),
1371 GetCrtcAction(outputs_[0].crtc,
1372 0, 0, kFirstMode, outputs_[0].output).c_str(),
1373 // First mode tried is expected to fail and it will
1374 // retry wil the 4th mode in the list.
1375 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3,
1376 outputs_[0].output).c_str(),
1377 // Then attempt to configure crtc1 with the first mode.
1378 GetCrtcAction(outputs_[1].crtc, 0, 0, kFirstMode,
1379 outputs_[1].output).c_str(),
1380 GetCrtcAction(outputs_[1].crtc, 0, 0, kFirstMode + 3,
1381 outputs_[1].output).c_str(),
1382 // Since it was requested to go into mirror mode
1383 // and the configured modes were different, it
1384 // should now try and setup a valid configurable
1385 // extended mode.
1386 GetFramebufferAction(
1387 outputs_[0].mode_infos[kFirstMode].width,
1388 outputs_[0].mode_infos[kFirstMode].height +
1389 outputs_[1].mode_infos[kFirstMode].height +
1390 OutputConfigurator::kVerticalGap,
1391 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1392 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode,
1393 outputs_[0].output).c_str(),
1394 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3,
1395 outputs_[0].output).c_str(),
1396 GetCrtcAction(outputs_[1].crtc, 0,
1397 outputs_[1].mode_infos[kFirstMode].height +
1398 OutputConfigurator::kVerticalGap, kFirstMode,
1399 outputs_[1].output).c_str(),
1400 GetCrtcAction(outputs_[1].crtc, 0,
1401 outputs_[1].mode_infos[kFirstMode].height +
1402 OutputConfigurator::kVerticalGap, kFirstMode + 3,
1403 outputs_[1].output).c_str(),
1404 kUngrab, kProjectingOn, NULL),
1405 delegate_->GetActionsAndClear());
1409 } // namespace chromeos