blob: 0749399af882a094c92e719c82017740865c5c5e [file] [log] [blame]
[email protected]6d980bc2012-09-10 19:28:451// 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
[email protected]acb217ed2013-04-09 21:52:367#include <cstdarg>
8#include <map>
[email protected]6d980bc2012-09-10 19:28:459#include <string>
[email protected]acb217ed2013-04-09 21:52:3610#include <vector>
[email protected]6d980bc2012-09-10 19:28:4511
[email protected]acb217ed2013-04-09 21:52:3612#include "base/basictypes.h"
13#include "base/compiler_specific.h"
[email protected]f129d2502013-07-17 22:45:5014#include "base/message_loop/message_loop.h"
[email protected]afa339d72013-06-11 06:32:5115#include "base/strings/stringprintf.h"
[email protected]6d980bc2012-09-10 19:28:4516#include "testing/gtest/include/gtest/gtest.h"
17
18namespace chromeos {
19
[email protected]acb217ed2013-04-09 21:52:3620namespace {
21
22// Strings returned by TestDelegate::GetActionsAndClear() to describe various
23// actions that were performed.
24const char kInitXRandR[] = "init";
25const char kUpdateXRandR[] = "update";
26const char kGrab[] = "grab";
27const char kUngrab[] = "ungrab";
28const char kSync[] = "sync";
29const char kForceDPMS[] = "dpms";
30const char kProjectingOn[] = "projecting";
31const char kProjectingOff[] = "not_projecting";
32
33// String returned by TestDelegate::GetActionsAndClear() if no actions were
34// requested.
35const char kNoActions[] = "";
36
37// Returns a string describing a TestDelegate::SetBackgroundColor() call.
38std::string GetBackgroundAction(uint32 color_argb) {
39 return base::StringPrintf("background(0x%x)", color_argb);
40}
41
42// Returns a string describing a TestDelegate::ConfigureCrtc() call.
43std::string GetCrtcAction(RRCrtc crtc,
44 int x,
45 int y,
46 RRMode mode,
47 RROutput output) {
48 return base::StringPrintf("crtc(crtc=%lu,x=%d,y=%d,mode=%lu,output=%lu)",
49 crtc, x, y, mode, output);
50}
51
52// Returns a string describing a TestDelegate::CreateFramebuffer() call.
53std::string GetFramebufferAction(int width,
54 int height,
55 RRCrtc crtc1,
56 RRCrtc crtc2) {
57 return base::StringPrintf(
58 "framebuffer(width=%d,height=%d,crtc1=%lu,crtc2=%lu)",
59 width, height, crtc1, crtc2);
60}
61
62// Returns a string describing a TestDelegate::ConfigureCTM() call.
63std::string GetCTMAction(
64 int device_id,
65 const OutputConfigurator::CoordinateTransformation& ctm) {
66 return base::StringPrintf("ctm(id=%d,transform=(%f,%f,%f,%f))", device_id,
67 ctm.x_scale, ctm.x_offset, ctm.y_scale, ctm.y_offset);
68}
69
70// Joins a sequence of strings describing actions (e.g. kScreenDim) such
71// that they can be compared against a string returned by
72// TestDelegate::GetActionsAndClear(). The list of actions must be
73// terminated by a NULL pointer.
74std::string JoinActions(const char* action, ...) {
75 std::string actions;
76
77 va_list arg_list;
78 va_start(arg_list, action);
79 while (action) {
80 if (!actions.empty())
81 actions += ",";
82 actions += action;
83 action = va_arg(arg_list, const char*);
84 }
85 va_end(arg_list);
86 return actions;
87}
88
89class TestDelegate : public OutputConfigurator::Delegate {
90 public:
91 static const int kXRandREventBase = 10;
92
[email protected]edc1c802013-08-14 03:55:0493 TestDelegate() : configure_crtc_result_(true) {}
[email protected]acb217ed2013-04-09 21:52:3694 virtual ~TestDelegate() {}
95
[email protected]edc1c802013-08-14 03:55:0496 const std::vector<OutputConfigurator::OutputSnapshot>& outputs() const {
97 return outputs_;
98 }
[email protected]acb217ed2013-04-09 21:52:3699 void set_outputs(
100 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
101 outputs_ = outputs;
102 }
103
[email protected]edc1c802013-08-14 03:55:04104 void set_configure_crtc_result(bool result) {
105 configure_crtc_result_ = result;
106 }
107
[email protected]acb217ed2013-04-09 21:52:36108 // Returns a comma-separated string describing the actions that were
109 // requested since the previous call to GetActionsAndClear() (i.e.
110 // results are non-repeatable).
111 std::string GetActionsAndClear() {
112 std::string actions = actions_;
113 actions_.clear();
114 return actions;
115 }
116
[email protected]acb217ed2013-04-09 21:52:36117 // OutputConfigurator::Delegate overrides:
118 virtual void SetPanelFittingEnabled(bool enabled) OVERRIDE {}
119 virtual void InitXRandRExtension(int* event_base) OVERRIDE {
120 AppendAction(kInitXRandR);
121 *event_base = kXRandREventBase;
122 }
123 virtual void UpdateXRandRConfiguration(
124 const base::NativeEvent& event) OVERRIDE { AppendAction(kUpdateXRandR); }
125 virtual void GrabServer() OVERRIDE { AppendAction(kGrab); }
126 virtual void UngrabServer() OVERRIDE { AppendAction(kUngrab); }
127 virtual void SyncWithServer() OVERRIDE { AppendAction(kSync); }
128 virtual void SetBackgroundColor(uint32 color_argb) OVERRIDE {
129 AppendAction(GetBackgroundAction(color_argb));
130 }
131 virtual void ForceDPMSOn() OVERRIDE { AppendAction(kForceDPMS); }
[email protected]a5792d32013-08-01 11:18:21132 virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs(
133 const OutputConfigurator::StateController* controller) OVERRIDE {
[email protected]acb217ed2013-04-09 21:52:36134 return outputs_;
135 }
[email protected]dd807f42013-08-09 01:53:30136 virtual bool ConfigureCrtc(RRCrtc crtc,
137 RRMode mode,
138 RROutput output,
139 int x,
140 int y) OVERRIDE {
141 AppendAction(GetCrtcAction(crtc, x, y, mode, output));
[email protected]edc1c802013-08-14 03:55:04142 return configure_crtc_result_;
[email protected]acb217ed2013-04-09 21:52:36143 }
144 virtual void CreateFrameBuffer(
145 int width,
146 int height,
[email protected]dd807f42013-08-09 01:53:30147 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
[email protected]42091902013-05-02 02:24:12148 AppendAction(
149 GetFramebufferAction(width,
150 height,
[email protected]dd807f42013-08-09 01:53:30151 outputs.size() >= 1 ? outputs[0].crtc : 0,
152 outputs.size() >= 2 ? outputs[1].crtc : 0));
[email protected]acb217ed2013-04-09 21:52:36153 }
154 virtual void ConfigureCTM(
155 int touch_device_id,
156 const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE {
157 AppendAction(GetCTMAction(touch_device_id, ctm));
158 }
159 virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE {
160 AppendAction(projecting ? kProjectingOn : kProjectingOff);
161 }
162
163 private:
164 struct ModeDetails {
165 ModeDetails() : width(0), height(0), interlaced(false) {}
166 ModeDetails(int width, int height, bool interlaced)
167 : width(width),
168 height(height),
169 interlaced(interlaced) {}
170
171 int width;
172 int height;
173 bool interlaced;
174 };
175
176 void AppendAction(const std::string& action) {
177 if (!actions_.empty())
178 actions_ += ",";
179 actions_ += action;
180 }
181
182 std::map<RRMode, ModeDetails> modes_;
183
184 // Outputs to be returned by GetOutputs().
185 std::vector<OutputConfigurator::OutputSnapshot> outputs_;
186
187 std::string actions_;
188
[email protected]edc1c802013-08-14 03:55:04189 // Return value returned by ConfigureCrtc().
190 bool configure_crtc_result_;
191
[email protected]acb217ed2013-04-09 21:52:36192 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
193};
194
195class TestStateController : public OutputConfigurator::StateController {
196 public:
197 TestStateController() : state_(STATE_DUAL_EXTENDED) {}
[email protected]42091902013-05-02 02:24:12198 virtual ~TestStateController() {}
[email protected]acb217ed2013-04-09 21:52:36199
200 void set_state(OutputState state) { state_ = state; }
201
202 // OutputConfigurator::StateController overrides:
[email protected]2c8a0aa72013-05-16 06:24:48203 virtual OutputState GetStateForDisplayIds(
204 const std::vector<int64>& outputs) const OVERRIDE { return state_; }
[email protected]a5792d32013-08-01 11:18:21205 virtual bool GetResolutionForDisplayId(
206 int64 display_id,
207 int *width,
208 int *height) const OVERRIDE {
209 return false;
210 }
[email protected]acb217ed2013-04-09 21:52:36211
212 private:
213 OutputState state_;
214
215 DISALLOW_COPY_AND_ASSIGN(TestStateController);
216};
217
[email protected]c1f30dc2013-05-22 17:27:45218class TestMirroringController
219 : public OutputConfigurator::SoftwareMirroringController {
220 public:
221 TestMirroringController() : software_mirroring_enabled_(false) {}
222 virtual ~TestMirroringController() {}
223
224 virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
225 software_mirroring_enabled_ = enabled;
226 }
227
228 bool software_mirroring_enabled() const {
229 return software_mirroring_enabled_;
230 }
231
232 private:
233 bool software_mirroring_enabled_;
234
235 DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
236};
237
[email protected]acb217ed2013-04-09 21:52:36238class OutputConfiguratorTest : public testing::Test {
239 public:
240 OutputConfiguratorTest()
241 : test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
242 virtual ~OutputConfiguratorTest() {}
243
244 virtual void SetUp() OVERRIDE {
245 delegate_ = new TestDelegate();
246 configurator_.SetDelegateForTesting(
247 scoped_ptr<OutputConfigurator::Delegate>(delegate_));
248 configurator_.set_state_controller(&state_controller_);
[email protected]c1f30dc2013-05-22 17:27:45249 configurator_.set_mirroring_controller(&mirroring_controller_);
[email protected]acb217ed2013-04-09 21:52:36250
[email protected]5d99ee62013-08-16 19:56:47251 OutputConfigurator::ModeInfo small_mode_info;
252 small_mode_info.width = kSmallModeWidth;
253 small_mode_info.height = kSmallModeHeight;
254
255 OutputConfigurator::ModeInfo big_mode_info;
256 big_mode_info.width = kBigModeWidth;
257 big_mode_info.height = kBigModeHeight;
258
[email protected]acb217ed2013-04-09 21:52:36259 OutputConfigurator::OutputSnapshot* o = &outputs_[0];
260 o->output = 1;
261 o->crtc = 10;
262 o->current_mode = kSmallModeId;
263 o->native_mode = kSmallModeId;
[email protected]a5792d32013-08-01 11:18:21264 o->selected_mode = kSmallModeId;
[email protected]acb217ed2013-04-09 21:52:36265 o->mirror_mode = kSmallModeId;
[email protected]dd807f42013-08-09 01:53:30266 o->x = 0;
[email protected]acb217ed2013-04-09 21:52:36267 o->y = 0;
[email protected]acb217ed2013-04-09 21:52:36268 o->is_internal = true;
269 o->is_aspect_preserving_scaling = true;
[email protected]5d99ee62013-08-16 19:56:47270 o->mode_infos[kSmallModeId] = small_mode_info;
[email protected]acb217ed2013-04-09 21:52:36271 o->touch_device_id = 0;
[email protected]2c8a0aa72013-05-16 06:24:48272 o->has_display_id = true;
[email protected]acb217ed2013-04-09 21:52:36273
274 o = &outputs_[1];
275 o->output = 2;
276 o->crtc = 11;
277 o->current_mode = kBigModeId;
278 o->native_mode = kBigModeId;
[email protected]a5792d32013-08-01 11:18:21279 o->selected_mode = kBigModeId;
[email protected]acb217ed2013-04-09 21:52:36280 o->mirror_mode = kSmallModeId;
[email protected]dd807f42013-08-09 01:53:30281 o->x = 0;
[email protected]acb217ed2013-04-09 21:52:36282 o->y = 0;
[email protected]acb217ed2013-04-09 21:52:36283 o->is_internal = false;
284 o->is_aspect_preserving_scaling = true;
[email protected]5d99ee62013-08-16 19:56:47285 o->mode_infos[kSmallModeId] = small_mode_info;
286 o->mode_infos[kBigModeId] = big_mode_info;
[email protected]acb217ed2013-04-09 21:52:36287 o->touch_device_id = 0;
[email protected]2c8a0aa72013-05-16 06:24:48288 o->has_display_id = true;
[email protected]acb217ed2013-04-09 21:52:36289
[email protected]edc1c802013-08-14 03:55:04290 UpdateOutputs(2, false);
[email protected]acb217ed2013-04-09 21:52:36291 }
292
[email protected]c1f30dc2013-05-22 17:27:45293 void DisableNativeMirroring() {
294 outputs_[0].mirror_mode = outputs_[1].mirror_mode = 0L;
295 }
296
[email protected]acb217ed2013-04-09 21:52:36297 protected:
298 // Predefined modes that can be used by outputs.
299 static const int kSmallModeId = 20;
300 static const int kSmallModeWidth = 1366;
301 static const int kSmallModeHeight = 768;
302
303 static const int kBigModeId = 21;
304 static const int kBigModeWidth = 2560;
305 static const int kBigModeHeight = 1600;
306
307 // Configures |delegate_| to return the first |num_outputs| entries from
[email protected]edc1c802013-08-14 03:55:04308 // |outputs_|. If |send_events| is true, also sends screen-change and
309 // output-change events to |configurator_| and triggers the configure
310 // timeout if one was scheduled.
311 void UpdateOutputs(size_t num_outputs, bool send_events) {
[email protected]acb217ed2013-04-09 21:52:36312 ASSERT_LE(num_outputs, arraysize(outputs_));
313 std::vector<OutputConfigurator::OutputSnapshot> outputs;
314 for (size_t i = 0; i < num_outputs; ++i)
315 outputs.push_back(outputs_[i]);
316 delegate_->set_outputs(outputs);
[email protected]edc1c802013-08-14 03:55:04317
318 if (send_events) {
319 test_api_.SendScreenChangeEvent();
320 for (size_t i = 0; i < arraysize(outputs_); ++i) {
321 const OutputConfigurator::OutputSnapshot output = outputs_[i];
322 bool connected = i < num_outputs;
323 test_api_.SendOutputChangeEvent(
324 output.output, output.crtc, output.current_mode, connected);
325 }
326 test_api_.TriggerConfigureTimeout();
327 }
[email protected]acb217ed2013-04-09 21:52:36328 }
329
330 // Initializes |configurator_| with a single internal display.
[email protected]edc1c802013-08-14 03:55:04331 void InitWithSingleOutput() {
332 UpdateOutputs(1, false);
[email protected]acb217ed2013-04-09 21:52:36333 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
[email protected]d30dac82013-07-31 16:17:30334 configurator_.Init(false);
335 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
336 configurator_.Start(0);
[email protected]acb217ed2013-04-09 21:52:36337 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
338 GetFramebufferAction(kSmallModeWidth,
339 kSmallModeHeight, outputs_[0].crtc, 0).c_str(),
340 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
341 outputs_[0].output).c_str(),
342 kForceDPMS, kUngrab, kProjectingOff, NULL),
343 delegate_->GetActionsAndClear());
344 }
345
346 base::MessageLoop message_loop_;
347 TestStateController state_controller_;
[email protected]c1f30dc2013-05-22 17:27:45348 TestMirroringController mirroring_controller_;
[email protected]acb217ed2013-04-09 21:52:36349 OutputConfigurator configurator_;
350 TestDelegate* delegate_; // not owned
351 OutputConfigurator::TestApi test_api_;
352
353 OutputConfigurator::OutputSnapshot outputs_[2];
354
355 private:
356 DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
357};
358
359} // namespace
[email protected]6d980bc2012-09-10 19:28:45360
[email protected]acb217ed2013-04-09 21:52:36361TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
362 InitWithSingleOutput();
363
364 // Connect a second output and check that the configurator enters
365 // extended mode.
[email protected]edc1c802013-08-14 03:55:04366 state_controller_.set_state(STATE_DUAL_EXTENDED);
367 UpdateOutputs(2, true);
[email protected]acb217ed2013-04-09 21:52:36368 const int kDualHeight =
369 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
[email protected]acb217ed2013-04-09 21:52:36370 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
371 GetFramebufferAction(kBigModeWidth, kDualHeight,
372 outputs_[0].crtc, outputs_[1].crtc).c_str(),
373 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
374 outputs_[0].output).c_str(),
375 GetCrtcAction(outputs_[1].crtc, 0,
376 kSmallModeHeight + OutputConfigurator::kVerticalGap,
377 kBigModeId, outputs_[1].output).c_str(),
378 kUngrab, kProjectingOn, NULL),
379 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45380 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36381
382 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
383 EXPECT_EQ(JoinActions(kGrab,
384 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
385 outputs_[0].crtc, outputs_[1].crtc).c_str(),
386 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
387 outputs_[0].output).c_str(),
388 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
389 outputs_[1].output).c_str(),
390 kUngrab, NULL),
391 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45392 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36393
394 // Disconnect the second output.
[email protected]edc1c802013-08-14 03:55:04395 UpdateOutputs(1, true);
[email protected]acb217ed2013-04-09 21:52:36396 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
397 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
398 outputs_[0].crtc, 0).c_str(),
399 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
400 outputs_[0].output).c_str(),
401 kUngrab, kProjectingOff, NULL),
402 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45403 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
404
405 // Software Mirroring
406 DisableNativeMirroring();
[email protected]c1f30dc2013-05-22 17:27:45407 state_controller_.set_state(STATE_DUAL_EXTENDED);
[email protected]edc1c802013-08-14 03:55:04408 UpdateOutputs(2, true);
[email protected]c1f30dc2013-05-22 17:27:45409 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
410 GetFramebufferAction(kBigModeWidth, kDualHeight,
411 outputs_[0].crtc, outputs_[1].crtc).c_str(),
412 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
413 outputs_[0].output).c_str(),
414 GetCrtcAction(outputs_[1].crtc, 0,
415 kSmallModeHeight + OutputConfigurator::kVerticalGap,
416 kBigModeId, outputs_[1].output).c_str(),
417 kUngrab, kProjectingOn, NULL),
418 delegate_->GetActionsAndClear());
419 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
420
421 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
422 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
423 delegate_->GetActionsAndClear());
424 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
425 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
426
[email protected]57bed4d2013-06-08 20:54:18427 // Setting STATE_DUAL_MIRROR should try to reconfigure
428 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
429 EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear());
430 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
431
432 // Set back to software mirror mode.
433 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
434 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
435 delegate_->GetActionsAndClear());
436 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
437 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
438
[email protected]c1f30dc2013-05-22 17:27:45439 // Disconnect the second output.
[email protected]edc1c802013-08-14 03:55:04440 UpdateOutputs(1, true);
[email protected]c1f30dc2013-05-22 17:27:45441 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
442 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
443 outputs_[0].crtc, 0).c_str(),
444 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
445 outputs_[0].output).c_str(),
446 kUngrab, kProjectingOff, NULL),
447 delegate_->GetActionsAndClear());
448 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36449}
450
451TEST_F(OutputConfiguratorTest, SetDisplayPower) {
452 InitWithSingleOutput();
453
[email protected]acb217ed2013-04-09 21:52:36454 state_controller_.set_state(STATE_DUAL_MIRROR);
[email protected]edc1c802013-08-14 03:55:04455 UpdateOutputs(2, true);
[email protected]acb217ed2013-04-09 21:52:36456 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
457 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
458 outputs_[0].crtc, outputs_[1].crtc).c_str(),
459 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
460 outputs_[0].output).c_str(),
461 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
462 outputs_[1].output).c_str(),
463 kUngrab, kProjectingOn, NULL),
464 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45465 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36466
467 // Turning off the internal display should switch the external display to
468 // its native mode.
469 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
470 OutputConfigurator::kSetDisplayPowerNoFlags);
471 EXPECT_EQ(JoinActions(kGrab,
472 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
473 outputs_[0].crtc, outputs_[1].crtc).c_str(),
474 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
475 outputs_[0].output).c_str(),
476 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
477 outputs_[1].output).c_str(),
478 kForceDPMS, kUngrab, NULL),
479 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45480 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
[email protected]acb217ed2013-04-09 21:52:36481
482 // When all displays are turned off, the framebuffer should switch back
483 // to the mirrored size.
484 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
485 OutputConfigurator::kSetDisplayPowerNoFlags);
486 EXPECT_EQ(JoinActions(kGrab,
487 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
488 outputs_[0].crtc, outputs_[1].crtc).c_str(),
489 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
490 outputs_[0].output).c_str(),
491 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
492 outputs_[1].output).c_str(),
493 kUngrab, NULL),
494 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45495 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
496 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36497
498 // Turn all displays on and check that mirroring is still used.
499 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
500 OutputConfigurator::kSetDisplayPowerNoFlags);
501 EXPECT_EQ(JoinActions(kGrab,
502 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
503 outputs_[0].crtc, outputs_[1].crtc).c_str(),
504 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
505 outputs_[0].output).c_str(),
506 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
507 outputs_[1].output).c_str(),
508 kForceDPMS, kUngrab, NULL),
509 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45510 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
511 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
512
513 // Software Mirroring
514 DisableNativeMirroring();
[email protected]edc1c802013-08-14 03:55:04515 state_controller_.set_state(STATE_DUAL_MIRROR);
516 UpdateOutputs(2, true);
[email protected]c1f30dc2013-05-22 17:27:45517 const int kDualHeight =
518 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
[email protected]c1f30dc2013-05-22 17:27:45519 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
520 GetFramebufferAction(kBigModeWidth, kDualHeight,
521 outputs_[0].crtc, outputs_[1].crtc).c_str(),
522 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
523 outputs_[0].output).c_str(),
524 GetCrtcAction(outputs_[1].crtc, 0,
525 kSmallModeHeight + OutputConfigurator::kVerticalGap,
526 kBigModeId, outputs_[1].output).c_str(),
527 kUngrab, kProjectingOn, NULL),
528 delegate_->GetActionsAndClear());
529 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
530 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
531
532 // Turning off the internal display should switch the external display to
533 // its native mode.
534 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
535 OutputConfigurator::kSetDisplayPowerNoFlags);
536 EXPECT_EQ(JoinActions(kGrab,
537 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
538 outputs_[0].crtc, outputs_[1].crtc).c_str(),
539 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
540 outputs_[0].output).c_str(),
541 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
542 outputs_[1].output).c_str(),
543 kForceDPMS, kUngrab, NULL),
544 delegate_->GetActionsAndClear());
545 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
546 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
547
548 // When all displays are turned off, the framebuffer should switch back
549 // to the extended + software mirroring.
550 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
551 OutputConfigurator::kSetDisplayPowerNoFlags);
552 EXPECT_EQ(JoinActions(kGrab,
553 GetFramebufferAction(kBigModeWidth, kDualHeight,
554 outputs_[0].crtc, outputs_[1].crtc).c_str(),
555 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
556 outputs_[0].output).c_str(),
557 GetCrtcAction(outputs_[1].crtc, 0,
558 kSmallModeHeight + OutputConfigurator::kVerticalGap,
559 0, outputs_[1].output).c_str(),
560 kUngrab, NULL),
561 delegate_->GetActionsAndClear());
562 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
563 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
564
565 // Turn all displays on and check that mirroring is still used.
566 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
567 OutputConfigurator::kSetDisplayPowerNoFlags);
568 EXPECT_EQ(JoinActions(kGrab,
569 GetFramebufferAction(kBigModeWidth, kDualHeight,
570 outputs_[0].crtc, outputs_[1].crtc).c_str(),
571 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
572 outputs_[0].output).c_str(),
573 GetCrtcAction(outputs_[1].crtc, 0,
574 kSmallModeHeight + OutputConfigurator::kVerticalGap,
575 kBigModeId, outputs_[1].output).c_str(),
576 kForceDPMS, kUngrab, NULL),
577 delegate_->GetActionsAndClear());
578 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
579 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
580
[email protected]acb217ed2013-04-09 21:52:36581}
582
583TEST_F(OutputConfiguratorTest, SuspendAndResume) {
584 InitWithSingleOutput();
585
586 // No preparation is needed before suspending when the display is already
587 // on. The configurator should still reprobe on resume in case a display
588 // was connected while suspended.
589 configurator_.SuspendDisplays();
590 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
591 configurator_.ResumeDisplays();
592 EXPECT_EQ(JoinActions(kGrab,
593 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
594 outputs_[0].crtc, 0).c_str(),
595 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
596 outputs_[0].output).c_str(),
597 kForceDPMS, kUngrab, NULL),
598 delegate_->GetActionsAndClear());
599
600 // Now turn the display off before suspending and check that the
601 // configurator turns it back on and syncs with the server.
602 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
603 OutputConfigurator::kSetDisplayPowerNoFlags);
604 EXPECT_EQ(JoinActions(kGrab,
605 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
606 outputs_[0].crtc, 0).c_str(),
607 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
608 outputs_[0].output).c_str(),
609 kUngrab, NULL),
610 delegate_->GetActionsAndClear());
611
612 configurator_.SuspendDisplays();
613 EXPECT_EQ(JoinActions(kGrab,
614 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
615 outputs_[0].crtc, 0).c_str(),
616 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
617 outputs_[0].output).c_str(),
618 kForceDPMS, kUngrab, kSync, NULL),
619 delegate_->GetActionsAndClear());
620
621 configurator_.ResumeDisplays();
622 EXPECT_EQ(JoinActions(kGrab,
623 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
624 outputs_[0].crtc, 0).c_str(),
625 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
626 outputs_[0].output).c_str(),
627 kForceDPMS, kUngrab, NULL),
628 delegate_->GetActionsAndClear());
629
630 // If a second, external display is connected, the displays shouldn't be
631 // powered back on before suspending.
[email protected]acb217ed2013-04-09 21:52:36632 state_controller_.set_state(STATE_DUAL_MIRROR);
[email protected]edc1c802013-08-14 03:55:04633 UpdateOutputs(2, true);
[email protected]acb217ed2013-04-09 21:52:36634 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
635 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
636 outputs_[0].crtc, outputs_[1].crtc).c_str(),
637 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
638 outputs_[0].output).c_str(),
639 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
640 outputs_[1].output).c_str(),
641 kUngrab, kProjectingOn, NULL),
642 delegate_->GetActionsAndClear());
643
644 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
645 OutputConfigurator::kSetDisplayPowerNoFlags);
646 EXPECT_EQ(JoinActions(kGrab,
647 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
648 outputs_[0].crtc, outputs_[1].crtc).c_str(),
649 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
650 outputs_[0].output).c_str(),
651 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
652 outputs_[1].output).c_str(),
653 kUngrab, NULL),
654 delegate_->GetActionsAndClear());
655
656 configurator_.SuspendDisplays();
657 EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
658 delegate_->GetActionsAndClear());
659
[email protected]edc1c802013-08-14 03:55:04660 // If a display is disconnected while suspended, the configurator should
[email protected]acb217ed2013-04-09 21:52:36661 // pick up the change.
[email protected]edc1c802013-08-14 03:55:04662 UpdateOutputs(1, false);
[email protected]acb217ed2013-04-09 21:52:36663 configurator_.ResumeDisplays();
664 EXPECT_EQ(JoinActions(kGrab,
665 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
666 outputs_[0].crtc, 0).c_str(),
667 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
668 outputs_[0].output).c_str(),
669 kUngrab, NULL),
670 delegate_->GetActionsAndClear());
671}
672
673TEST_F(OutputConfiguratorTest, Headless) {
[email protected]edc1c802013-08-14 03:55:04674 UpdateOutputs(0, false);
[email protected]acb217ed2013-04-09 21:52:36675 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
[email protected]d30dac82013-07-31 16:17:30676 configurator_.Init(false);
677 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
678 configurator_.Start(0);
[email protected]acb217ed2013-04-09 21:52:36679 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab,
680 kProjectingOff, NULL),
681 delegate_->GetActionsAndClear());
682
683 // Not much should happen when the display power state is changed while
684 // no displays are connected.
685 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
686 OutputConfigurator::kSetDisplayPowerNoFlags);
687 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
688 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
689 OutputConfigurator::kSetDisplayPowerNoFlags);
690 EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
691 delegate_->GetActionsAndClear());
692
693 // Connect an external display and check that it's configured correctly.
[email protected]5d99ee62013-08-16 19:56:47694 outputs_[0] = outputs_[1];
[email protected]edc1c802013-08-14 03:55:04695 UpdateOutputs(1, true);
[email protected]acb217ed2013-04-09 21:52:36696 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
697 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
698 outputs_[0].crtc, 0).c_str(),
699 GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId,
700 outputs_[0].output).c_str(),
701 kUngrab, kProjectingOff, NULL),
702 delegate_->GetActionsAndClear());
703}
704
705TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
[email protected]edc1c802013-08-14 03:55:04706 UpdateOutputs(2, false);
[email protected]acb217ed2013-04-09 21:52:36707 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
[email protected]d30dac82013-07-31 16:17:30708 configurator_.Init(false);
709 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
[email protected]acb217ed2013-04-09 21:52:36710
711 state_controller_.set_state(STATE_DUAL_MIRROR);
[email protected]d30dac82013-07-31 16:17:30712 configurator_.Start(0);
[email protected]acb217ed2013-04-09 21:52:36713 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
714 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
715 outputs_[0].crtc, outputs_[1].crtc).c_str(),
716 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
717 outputs_[0].output).c_str(),
718 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
719 outputs_[1].output).c_str(),
720 kForceDPMS, kUngrab, kProjectingOn, NULL),
721 delegate_->GetActionsAndClear());
722}
723
724TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
[email protected]edc1c802013-08-14 03:55:04725 UpdateOutputs(0, false);
[email protected]acb217ed2013-04-09 21:52:36726 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
[email protected]d30dac82013-07-31 16:17:30727 configurator_.Init(false);
728 configurator_.Start(0);
[email protected]acb217ed2013-04-09 21:52:36729 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
730 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
731 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
732 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
733
[email protected]edc1c802013-08-14 03:55:04734 UpdateOutputs(1, true);
[email protected]acb217ed2013-04-09 21:52:36735 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
736 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
737 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
738 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
739
[email protected]acb217ed2013-04-09 21:52:36740 state_controller_.set_state(STATE_DUAL_EXTENDED);
[email protected]edc1c802013-08-14 03:55:04741 UpdateOutputs(2, true);
[email protected]acb217ed2013-04-09 21:52:36742 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
743 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
744 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
745 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
746}
747
[email protected]edc1c802013-08-14 03:55:04748TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithoutId) {
[email protected]2c8a0aa72013-05-16 06:24:48749 outputs_[0].has_display_id = false;
[email protected]edc1c802013-08-14 03:55:04750 UpdateOutputs(2, false);
[email protected]d30dac82013-07-31 16:17:30751 configurator_.Init(false);
[email protected]2c8a0aa72013-05-16 06:24:48752 state_controller_.set_state(STATE_DUAL_MIRROR);
[email protected]edc1c802013-08-14 03:55:04753 configurator_.Start(0);
[email protected]2c8a0aa72013-05-16 06:24:48754 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
[email protected]edc1c802013-08-14 03:55:04755}
[email protected]2c8a0aa72013-05-16 06:24:48756
[email protected]edc1c802013-08-14 03:55:04757TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithId) {
[email protected]2c8a0aa72013-05-16 06:24:48758 outputs_[0].has_display_id = true;
[email protected]edc1c802013-08-14 03:55:04759 UpdateOutputs(2, false);
760 configurator_.Init(false);
761 state_controller_.set_state(STATE_DUAL_MIRROR);
762 configurator_.Start(0);
[email protected]2c8a0aa72013-05-16 06:24:48763 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
764}
765
[email protected]edc1c802013-08-14 03:55:04766TEST_F(OutputConfiguratorTest, AvoidUnnecessaryProbes) {
767 InitWithSingleOutput();
768
769 // X sends several events just after the configurator starts. Check that
770 // the output change events don't trigger an additional probe, which can
771 // block the UI thread.
772 test_api_.SendScreenChangeEvent();
773 EXPECT_EQ(kUpdateXRandR, delegate_->GetActionsAndClear());
774
775 test_api_.SendOutputChangeEvent(
776 outputs_[0].output, outputs_[0].crtc, outputs_[0].current_mode, true);
777 test_api_.SendOutputChangeEvent(
778 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
779 EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
780 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
781
782 // Send an event stating that the second output is connected and check
783 // that it gets updated.
784 state_controller_.set_state(STATE_DUAL_MIRROR);
785 UpdateOutputs(2, false);
786 test_api_.SendOutputChangeEvent(
787 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, true);
788 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
789 EXPECT_EQ(JoinActions(kGrab,
790 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
791 outputs_[0].crtc, outputs_[1].crtc).c_str(),
792 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
793 outputs_[0].output).c_str(),
794 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
795 outputs_[1].output).c_str(),
796 kUngrab, kProjectingOn, NULL),
797 delegate_->GetActionsAndClear());
798
799 // An event about the second output changing modes should trigger another
800 // reconfigure.
801 test_api_.SendOutputChangeEvent(
802 outputs_[1].output, outputs_[1].crtc, outputs_[1].native_mode, true);
803 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
804 EXPECT_EQ(JoinActions(kGrab,
805 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
806 outputs_[0].crtc, outputs_[1].crtc).c_str(),
807 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
808 outputs_[0].output).c_str(),
809 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
810 outputs_[1].output).c_str(),
811 kUngrab, kProjectingOn, NULL),
812 delegate_->GetActionsAndClear());
813
814 // Disconnect the second output.
815 UpdateOutputs(1, true);
816 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
817 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
818 outputs_[0].crtc, 0).c_str(),
819 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
820 outputs_[0].output).c_str(),
821 kUngrab, kProjectingOff, NULL),
822 delegate_->GetActionsAndClear());
823
824 // An additional event about the second output being disconnected should
825 // be ignored.
826 test_api_.SendOutputChangeEvent(
827 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
828 EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
829 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
830
831 // Tell the delegate to report failure, which should result in the
832 // second output sticking with its native mode.
833 delegate_->set_configure_crtc_result(false);
834 UpdateOutputs(2, true);
835 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
836 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
837 outputs_[0].crtc, outputs_[1].crtc).c_str(),
838 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
839 outputs_[0].output).c_str(),
840 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
841 outputs_[1].output).c_str(),
842 kUngrab, kProjectingOn, NULL),
843 delegate_->GetActionsAndClear());
844
845 // An change event reporting a mode change on the second output should
846 // trigger another reconfigure.
847 delegate_->set_configure_crtc_result(true);
848 test_api_.SendOutputChangeEvent(
849 outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true);
850 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
851 EXPECT_EQ(JoinActions(kGrab,
852 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
853 outputs_[0].crtc, outputs_[1].crtc).c_str(),
854 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
855 outputs_[0].output).c_str(),
856 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
857 outputs_[1].output).c_str(),
858 kUngrab, kProjectingOn, NULL),
859 delegate_->GetActionsAndClear());
860}
861
[email protected]6d980bc2012-09-10 19:28:45862} // namespace chromeos