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"
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"
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
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
,
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
,
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(
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
, ...) {
89 va_start(arg_list
, action
);
94 action
= va_arg(arg_list
, const char*);
100 class TestDelegate
: public OutputConfigurator::Delegate
{
102 static const int kXRandREventBase
= 10;
105 : max_configurable_pixels_(0),
106 hdcp_state_(HDCP_STATE_UNDESIRED
) {}
107 virtual ~TestDelegate() {}
109 const std::vector
<OutputConfigurator::OutputSnapshot
>& outputs() const {
113 const std::vector
<OutputConfigurator::OutputSnapshot
>& 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_
;
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()
155 virtual void AddOutputMode(RROutput output
, RRMode mode
) OVERRIDE
{
156 AppendAction(GetAddOutputModeAction(output
, mode
));
158 virtual bool ConfigureCrtc(RRCrtc crtc
,
163 AppendAction(GetCrtcAction(crtc
, x
, y
, mode
, output
));
165 if (max_configurable_pixels_
== 0)
168 OutputConfigurator::OutputSnapshot
* snapshot
= GetOutputFromId(output
);
172 const OutputConfigurator::ModeInfo
* mode_info
=
173 OutputConfigurator::GetModeInfo(*snapshot
, mode
);
177 return mode_info
->width
* mode_info
->height
<= max_configurable_pixels_
;
180 virtual void CreateFrameBuffer(
183 const std::vector
<OutputConfigurator::OutputSnapshot
>& outputs
) OVERRIDE
{
185 GetFramebufferAction(width
,
187 outputs
.size() >= 1 ? outputs
[0].crtc
: 0,
188 outputs
.size() >= 2 ? outputs
[1].crtc
: 0));
190 virtual void ConfigureCTM(
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_
;
205 virtual bool SetHDCPState(RROutput id
, HDCPState state
) OVERRIDE
{
206 AppendAction(GetSetHDCPStateAction(id
, state
));
212 ModeDetails() : width(0), height(0), interlaced(false) {}
213 ModeDetails(int width
, int height
, bool interlaced
)
216 interlaced(interlaced
) {}
223 void AppendAction(const std::string
& action
) {
224 if (!actions_
.empty())
229 OutputConfigurator::OutputSnapshot
* GetOutputFromId(RROutput output_id
) {
230 for (unsigned int i
= 0; i
< outputs_
.size(); i
++) {
231 if (outputs_
[i
].output
== output_id
)
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
{
263 explicit TestObserver(OutputConfigurator
* configurator
)
264 : configurator_(configurator
) {
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()
276 return latest_outputs_
;
278 OutputState
latest_failed_state() const { return latest_failed_state_
; }
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
{
291 latest_outputs_
= outputs
;
294 virtual void OnDisplayModeChangeFailed(OutputState failed_new_state
)
297 latest_failed_state_
= failed_new_state
;
301 OutputConfigurator
* configurator_
; // Not owned.
303 // Number of times that OnDisplayMode*() has been called.
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
{
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(
327 int *height
) const OVERRIDE
{
334 DISALLOW_COPY_AND_ASSIGN(TestStateController
);
337 class TestMirroringController
338 : public OutputConfigurator::SoftwareMirroringController
{
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_
;
352 bool software_mirroring_enabled_
;
354 DISALLOW_COPY_AND_ASSIGN(TestMirroringController
);
357 class OutputConfiguratorTest
: public testing::Test
{
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];
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;
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;
413 UpdateOutputs(2, false);
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
);
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];
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;
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);
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);
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);
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
,
509 // Should pick highest refresh rate.
510 EXPECT_EQ(13u, OutputConfigurator::FindOutputModeMatchingSize(output
,
513 // Should pick non-interlaced mode.
514 EXPECT_EQ(17u, OutputConfigurator::FindOutputModeMatchingSize(output
,
517 // Interlaced only. Should pick one with the highest refresh rate in
519 EXPECT_EQ(20u, OutputConfigurator::FindOutputModeMatchingSize(output
,
522 // Mixed: Should pick one with the highest refresh rate in
524 EXPECT_EQ(23u, OutputConfigurator::FindOutputModeMatchingSize(output
,
527 // Just one interlaced mode.
528 EXPECT_EQ(24u, OutputConfigurator::FindOutputModeMatchingSize(output
,
531 // Refresh rate not available.
532 EXPECT_EQ(25u, OutputConfigurator::FindOutputModeMatchingSize(output
,
536 EXPECT_EQ(0u, OutputConfigurator::FindOutputModeMatchingSize(output
,
540 TEST_F(OutputConfiguratorTest
, ConnectSecondOutput
) {
541 InitWithSingleOutput();
543 // Connect a second output and check that the configurator enters
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());
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(),
573 delegate_
->GetActionsAndClear());
574 EXPECT_FALSE(mirroring_controller_
.software_mirroring_enabled());
575 EXPECT_EQ(1, observer_
.num_changes());
577 // Disconnect the second output.
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());
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.
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.
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.
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
);
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
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.
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(),
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.
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
);
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
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.
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(),
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.
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(),
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(),
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(),
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(),
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);
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);
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);
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
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
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
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
);
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();
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
,
1217 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL
), link_mask
);
1218 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE
),
1220 EXPECT_EQ(kNoActions
, delegate_
->GetActionsAndClear());
1223 UpdateOutputs(2, true);
1224 EXPECT_NE(kNoActions
, delegate_
->GetActionsAndClear());
1225 EXPECT_TRUE(configurator_
.QueryOutputProtectionStatus(id
,
1226 outputs_
[1].display_id
,
1229 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI
),
1231 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE
),
1233 EXPECT_EQ(kNoActions
, delegate_
->GetActionsAndClear());
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
,
1248 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI
), link_mask
);
1249 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP
),
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.
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
,
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
,
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.
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());
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
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
,
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
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