Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1760)

Side by Side Diff: chromeos/display/output_configurator_unittest.cc

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

Powered by Google App Engine
This is Rietveld 408576698