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
->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;
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;
415 UpdateOutputs(2, false);
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
);
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];
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;
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);
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);
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);
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
,
511 // Should pick highest refresh rate.
512 EXPECT_EQ(13u, OutputConfigurator::FindOutputModeMatchingSize(output
,
515 // Should pick non-interlaced mode.
516 EXPECT_EQ(17u, OutputConfigurator::FindOutputModeMatchingSize(output
,
519 // Interlaced only. Should pick one with the highest refresh rate in
521 EXPECT_EQ(20u, OutputConfigurator::FindOutputModeMatchingSize(output
,
524 // Mixed: Should pick one with the highest refresh rate in
526 EXPECT_EQ(23u, OutputConfigurator::FindOutputModeMatchingSize(output
,
529 // Just one interlaced mode.
530 EXPECT_EQ(24u, OutputConfigurator::FindOutputModeMatchingSize(output
,
533 // Refresh rate not available.
534 EXPECT_EQ(25u, OutputConfigurator::FindOutputModeMatchingSize(output
,
538 EXPECT_EQ(0u, OutputConfigurator::FindOutputModeMatchingSize(output
,
542 TEST_F(OutputConfiguratorTest
, ConnectSecondOutput
) {
543 InitWithSingleOutput();
545 // Connect a second output and check that the configurator enters
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());
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(),
575 delegate_
->GetActionsAndClear());
576 EXPECT_FALSE(mirroring_controller_
.software_mirroring_enabled());
577 EXPECT_EQ(1, observer_
.num_changes());
579 // Disconnect the second output.
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());
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.
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.
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.
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
);
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
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.
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(),
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.
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
);
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
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.
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(),
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.
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(),
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(),
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(),
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);
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);
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);
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
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
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
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
);
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();
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
,
1178 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL
), link_mask
);
1179 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE
),
1181 EXPECT_EQ(kNoActions
, delegate_
->GetActionsAndClear());
1184 UpdateOutputs(2, true);
1185 EXPECT_NE(kNoActions
, delegate_
->GetActionsAndClear());
1186 EXPECT_TRUE(configurator_
.QueryOutputProtectionStatus(id
,
1187 outputs_
[1].display_id
,
1190 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI
),
1192 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE
),
1194 EXPECT_EQ(kNoActions
, delegate_
->GetActionsAndClear());
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
,
1209 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI
), link_mask
);
1210 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP
),
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.
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
,
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
,
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.
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());
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
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
,
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
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