OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chromeos/display/output_configurator.h" | 5 #include "chromeos/display/output_configurator.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <cstdarg> | 8 #include <cstdarg> |
9 #include <map> | 9 #include <map> |
10 #include <string> | 10 #include <string> |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
95 } | 95 } |
96 va_end(arg_list); | 96 va_end(arg_list); |
97 return actions; | 97 return actions; |
98 } | 98 } |
99 | 99 |
100 class TestDelegate : public OutputConfigurator::Delegate { | 100 class TestDelegate : public OutputConfigurator::Delegate { |
101 public: | 101 public: |
102 static const int kXRandREventBase = 10; | 102 static const int kXRandREventBase = 10; |
103 | 103 |
104 TestDelegate() | 104 TestDelegate() |
105 : configure_crtc_result_(true), | 105 : max_configurable_pixels_(0), |
106 hdcp_state_(HDCP_STATE_UNDESIRED) {} | 106 hdcp_state_(HDCP_STATE_UNDESIRED) {} |
107 virtual ~TestDelegate() {} | 107 virtual ~TestDelegate() {} |
108 | 108 |
109 const std::vector<OutputConfigurator::OutputSnapshot>& outputs() const { | 109 const std::vector<OutputConfigurator::OutputSnapshot>& outputs() const { |
110 return outputs_; | 110 return outputs_; |
111 } | 111 } |
112 void set_outputs( | 112 void set_outputs( |
113 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { | 113 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { |
114 outputs_ = outputs; | 114 outputs_ = outputs; |
115 } | 115 } |
116 | 116 |
117 void set_configure_crtc_result(bool result) { | 117 void set_max_configurable_pixels(int pixels) { |
118 configure_crtc_result_ = result; | 118 max_configurable_pixels_ = pixels; |
119 } | 119 } |
120 | 120 |
121 void set_hdcp_state(HDCPState state) { hdcp_state_ = state; } | 121 void set_hdcp_state(HDCPState state) { hdcp_state_ = state; } |
122 | 122 |
123 // Returns a comma-separated string describing the actions that were | 123 // Returns a comma-separated string describing the actions that were |
124 // requested since the previous call to GetActionsAndClear() (i.e. | 124 // requested since the previous call to GetActionsAndClear() (i.e. |
125 // results are non-repeatable). | 125 // results are non-repeatable). |
126 std::string GetActionsAndClear() { | 126 std::string GetActionsAndClear() { |
127 std::string actions = actions_; | 127 std::string actions = actions_; |
128 actions_.clear(); | 128 actions_.clear(); |
(...skipping 25 matching lines...) Expand all Loading... | |
154 } | 154 } |
155 virtual void AddOutputMode(RROutput output, RRMode mode) OVERRIDE { | 155 virtual void AddOutputMode(RROutput output, RRMode mode) OVERRIDE { |
156 AppendAction(GetAddOutputModeAction(output, mode)); | 156 AppendAction(GetAddOutputModeAction(output, mode)); |
157 } | 157 } |
158 virtual bool ConfigureCrtc(RRCrtc crtc, | 158 virtual bool ConfigureCrtc(RRCrtc crtc, |
159 RRMode mode, | 159 RRMode mode, |
160 RROutput output, | 160 RROutput output, |
161 int x, | 161 int x, |
162 int y) OVERRIDE { | 162 int y) OVERRIDE { |
163 AppendAction(GetCrtcAction(crtc, x, y, mode, output)); | 163 AppendAction(GetCrtcAction(crtc, x, y, mode, output)); |
164 return configure_crtc_result_; | 164 |
165 if (max_configurable_pixels_ == 0) | |
166 return true; | |
167 | |
168 OutputConfigurator::OutputSnapshot* snapshot = GetOutputFromId(output); | |
169 | |
Daniel Erat
2014/01/09 00:40:34
nit: remove this blank line
| |
170 if (!snapshot) | |
171 return false; | |
172 | |
173 const OutputConfigurator::ModeInfo* mode_info = | |
174 OutputConfigurator::GetModeInfo(*snapshot, mode); | |
175 | |
Daniel Erat
2014/01/09 00:40:34
nit: remove this blank line
| |
176 if (!mode_info) | |
177 return false; | |
178 | |
179 return mode_info->width * mode_info->height <= max_configurable_pixels_; | |
180 | |
165 } | 181 } |
166 virtual void CreateFrameBuffer( | 182 virtual void CreateFrameBuffer( |
167 int width, | 183 int width, |
168 int height, | 184 int height, |
169 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE { | 185 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE { |
170 AppendAction( | 186 AppendAction( |
171 GetFramebufferAction(width, | 187 GetFramebufferAction(width, |
172 height, | 188 height, |
173 outputs.size() >= 1 ? outputs[0].crtc : 0, | 189 outputs.size() >= 1 ? outputs[0].crtc : 0, |
174 outputs.size() >= 2 ? outputs[1].crtc : 0)); | 190 outputs.size() >= 2 ? outputs[1].crtc : 0)); |
(...skipping 30 matching lines...) Expand all Loading... | |
205 int height; | 221 int height; |
206 bool interlaced; | 222 bool interlaced; |
207 }; | 223 }; |
208 | 224 |
209 void AppendAction(const std::string& action) { | 225 void AppendAction(const std::string& action) { |
210 if (!actions_.empty()) | 226 if (!actions_.empty()) |
211 actions_ += ","; | 227 actions_ += ","; |
212 actions_ += action; | 228 actions_ += action; |
213 } | 229 } |
214 | 230 |
231 OutputConfigurator::OutputSnapshot* GetOutputFromId(RROutput output_id) { | |
232 for (unsigned int i = 0; i < outputs_.size(); i++) { | |
233 if (outputs_[i].output == output_id) | |
234 return &outputs_[i]; | |
235 } | |
236 return NULL; | |
237 } | |
238 | |
215 std::map<RRMode, ModeDetails> modes_; | 239 std::map<RRMode, ModeDetails> modes_; |
216 | 240 |
217 // Most-recently-configured transformation matrices, keyed by touch device ID. | 241 // Most-recently-configured transformation matrices, keyed by touch device ID. |
218 std::map<int, OutputConfigurator::CoordinateTransformation> ctms_; | 242 std::map<int, OutputConfigurator::CoordinateTransformation> ctms_; |
219 | 243 |
220 // Outputs to be returned by GetOutputs(). | 244 // Outputs to be returned by GetOutputs(). |
221 std::vector<OutputConfigurator::OutputSnapshot> outputs_; | 245 std::vector<OutputConfigurator::OutputSnapshot> outputs_; |
222 | 246 |
223 std::string actions_; | 247 std::string actions_; |
224 | 248 |
225 // Return value returned by ConfigureCrtc(). | 249 // |max_configurable_pixels_| represents the maximum number of pixels that |
226 bool configure_crtc_result_; | 250 // ConfigureCrtc will support. Tests can use this to force ConfigureCrtc |
251 // to fail if attempting to set a resolution that is higher than what | |
252 // a device might support under a given circumstance. | |
253 // A value of 0 means that no limit is enforced and ConfigureCrtc will | |
254 // return success regardless of the resolution. | |
255 int max_configurable_pixels_; | |
227 | 256 |
228 // Result value of GetHDCPState(). | 257 // Result value of GetHDCPState(). |
229 HDCPState hdcp_state_; | 258 HDCPState hdcp_state_; |
230 | 259 |
231 DISALLOW_COPY_AND_ASSIGN(TestDelegate); | 260 DISALLOW_COPY_AND_ASSIGN(TestDelegate); |
232 }; | 261 }; |
233 | 262 |
234 class TestObserver : public OutputConfigurator::Observer { | 263 class TestObserver : public OutputConfigurator::Observer { |
235 public: | 264 public: |
236 explicit TestObserver(OutputConfigurator* configurator) | 265 explicit TestObserver(OutputConfigurator* configurator) |
(...skipping 775 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1012 kUngrab, kProjectingOff, NULL), | 1041 kUngrab, kProjectingOff, NULL), |
1013 delegate_->GetActionsAndClear()); | 1042 delegate_->GetActionsAndClear()); |
1014 | 1043 |
1015 // An additional event about the second output being disconnected should | 1044 // An additional event about the second output being disconnected should |
1016 // be ignored. | 1045 // be ignored. |
1017 test_api_.SendOutputChangeEvent( | 1046 test_api_.SendOutputChangeEvent( |
1018 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false); | 1047 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false); |
1019 EXPECT_FALSE(test_api_.TriggerConfigureTimeout()); | 1048 EXPECT_FALSE(test_api_.TriggerConfigureTimeout()); |
1020 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); | 1049 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); |
1021 | 1050 |
1022 // Tell the delegate to report failure, which should result in the | 1051 // Lower the limit for which the delegate will succeed, which should result |
1023 // second output sticking with its native mode. | 1052 // in the second output sticking with its native mode. |
1024 delegate_->set_configure_crtc_result(false); | 1053 delegate_->set_max_configurable_pixels(1); |
1025 UpdateOutputs(2, true); | 1054 UpdateOutputs(2, true); |
1026 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, | 1055 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, |
1027 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, | 1056 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, |
1028 outputs_[0].crtc, outputs_[1].crtc).c_str(), | 1057 outputs_[0].crtc, outputs_[1].crtc).c_str(), |
1029 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, | 1058 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, |
1030 outputs_[0].output).c_str(), | 1059 outputs_[0].output).c_str(), |
1031 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, | 1060 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, |
1032 outputs_[1].output).c_str(), | 1061 outputs_[1].output).c_str(), |
1062 GetFramebufferAction(kBigModeWidth, | |
1063 kSmallModeHeight + kBigModeHeight + | |
1064 OutputConfigurator::kVerticalGap, | |
1065 outputs_[0].crtc, outputs_[1].crtc).c_str(), | |
1066 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, | |
1067 outputs_[0].output).c_str(), | |
1068 GetCrtcAction(outputs_[1].crtc, 0, kSmallModeHeight + | |
1069 OutputConfigurator::kVerticalGap, kBigModeId, | |
1070 outputs_[1].output).c_str(), | |
1071 GetCrtcAction(outputs_[1].crtc, 0, kSmallModeHeight + | |
1072 OutputConfigurator::kVerticalGap, kSmallModeId, | |
1073 outputs_[1].output).c_str(), | |
1033 kUngrab, kProjectingOn, NULL), | 1074 kUngrab, kProjectingOn, NULL), |
1034 delegate_->GetActionsAndClear()); | 1075 delegate_->GetActionsAndClear()); |
1035 | 1076 |
1036 // An change event reporting a mode change on the second output should | 1077 // A change event reporting a mode change on the second output should |
1037 // trigger another reconfigure. | 1078 // trigger another reconfigure. |
1038 delegate_->set_configure_crtc_result(true); | 1079 delegate_->set_max_configurable_pixels(0); |
1039 test_api_.SendOutputChangeEvent( | 1080 test_api_.SendOutputChangeEvent( |
1040 outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true); | 1081 outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true); |
1041 EXPECT_TRUE(test_api_.TriggerConfigureTimeout()); | 1082 EXPECT_TRUE(test_api_.TriggerConfigureTimeout()); |
1042 EXPECT_EQ(JoinActions(kGrab, | 1083 EXPECT_EQ(JoinActions(kGrab, |
1043 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, | 1084 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight, |
1044 outputs_[0].crtc, outputs_[1].crtc).c_str(), | 1085 outputs_[0].crtc, outputs_[1].crtc).c_str(), |
1045 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, | 1086 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId, |
1046 outputs_[0].output).c_str(), | 1087 outputs_[0].output).c_str(), |
1047 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, | 1088 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId, |
1048 outputs_[1].output).c_str(), | 1089 outputs_[1].output).c_str(), |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1256 EXPECT_EQ(kSmallModeHeight + OutputConfigurator::kVerticalGap, | 1297 EXPECT_EQ(kSmallModeHeight + OutputConfigurator::kVerticalGap, |
1257 round((kDualHeight - 1) * ctm2.y_offset)); | 1298 round((kDualHeight - 1) * ctm2.y_offset)); |
1258 | 1299 |
1259 EXPECT_EQ(kSmallModeWidth - 1, round((kDualWidth - 1) * ctm1.x_scale)); | 1300 EXPECT_EQ(kSmallModeWidth - 1, round((kDualWidth - 1) * ctm1.x_scale)); |
1260 EXPECT_EQ(0, round((kDualWidth - 1) * ctm1.x_offset)); | 1301 EXPECT_EQ(0, round((kDualWidth - 1) * ctm1.x_offset)); |
1261 | 1302 |
1262 EXPECT_EQ(kBigModeWidth - 1, round((kDualWidth - 1) * ctm2.x_scale)); | 1303 EXPECT_EQ(kBigModeWidth - 1, round((kDualWidth - 1) * ctm2.x_scale)); |
1263 EXPECT_EQ(0, round((kDualWidth - 1) * ctm2.x_offset)); | 1304 EXPECT_EQ(0, round((kDualWidth - 1) * ctm2.x_offset)); |
1264 } | 1305 } |
1265 | 1306 |
1307 TEST_F(OutputConfiguratorTest, HandleConfigureCrtcFailure) { | |
1308 InitWithSingleOutput(); | |
1309 | |
1310 // kFirstMode represents the first mode in the list and | |
1311 // also the mode that we are requesting the output_configurator | |
1312 // to choose. The test will be setup so that this mode will fail | |
1313 // and it will have to choose the next best option. | |
1314 const int kFirstMode = 11; | |
1315 int current_mode = kFirstMode; | |
Daniel Erat
2014/01/09 00:40:34
nit: move this definition down to the place where
| |
1316 | |
1317 // Give the mode_info lists a few reasonable modes. | |
1318 for (int i = 0; i < 2; i++) { | |
1319 outputs_[i].mode_infos.clear(); | |
1320 | |
1321 current_mode = kFirstMode; | |
1322 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo( | |
1323 2560, 1600, false, 60.0); | |
1324 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo( | |
1325 1024, 768, false, 60.0); | |
1326 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo( | |
1327 1280, 720, false, 60.0); | |
1328 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo( | |
1329 1920, 1080, false, 60.0); | |
1330 outputs_[i].mode_infos[current_mode++] = OutputConfigurator::ModeInfo( | |
1331 1920, 1080, false, 40.0); | |
1332 | |
1333 outputs_[i].current_mode = kFirstMode; | |
1334 outputs_[i].native_mode = kFirstMode; | |
1335 } | |
1336 | |
1337 configurator_.Init(false); | |
1338 | |
1339 // First test simply fails in STATE_SINGLE mode. This is probably | |
1340 // unrealistic but the want to make sure any assumptions don't | |
1341 // creep in. | |
1342 delegate_->set_max_configurable_pixels( | |
1343 outputs_[0].mode_infos[kFirstMode + 2].width * | |
1344 outputs_[0].mode_infos[kFirstMode + 2].height); | |
1345 state_controller_.set_state(STATE_SINGLE); | |
1346 UpdateOutputs(1, true); | |
1347 | |
1348 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, | |
1349 GetFramebufferAction(2560, 1600, | |
1350 outputs_[0].crtc, 0).c_str(), | |
1351 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode, | |
1352 outputs_[0].output).c_str(), | |
1353 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3, | |
1354 outputs_[0].output).c_str(), | |
1355 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 2, | |
1356 outputs_[0].output).c_str(), | |
1357 kUngrab, kProjectingOff, NULL), | |
1358 delegate_->GetActionsAndClear()); | |
1359 | |
1360 // This test should attempt to configure a mirror mode that will not succeed | |
1361 // and should end up in extended mode. | |
1362 delegate_->set_max_configurable_pixels( | |
1363 outputs_[0].mode_infos[kFirstMode + 3].width * | |
1364 outputs_[0].mode_infos[kFirstMode + 3].height); | |
1365 state_controller_.set_state(STATE_DUAL_MIRROR); | |
1366 UpdateOutputs(2, true); | |
1367 | |
1368 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, | |
1369 GetFramebufferAction( | |
1370 outputs_[0].mode_infos[kFirstMode].width, | |
1371 outputs_[0].mode_infos[kFirstMode].height, | |
1372 outputs_[0].crtc, | |
1373 outputs_[1].crtc).c_str(), | |
1374 GetCrtcAction(outputs_[0].crtc, | |
1375 0, 0, kFirstMode, outputs_[0].output).c_str(), | |
1376 // First mode tried is expected to fail and it will | |
1377 // retry wil the 4th mode in the list. | |
1378 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3, | |
1379 outputs_[0].output).c_str(), | |
1380 // Then attempt to configure crtc1 with the first mode. | |
1381 GetCrtcAction(outputs_[1].crtc, 0, 0, kFirstMode, | |
1382 outputs_[1].output).c_str(), | |
1383 GetCrtcAction(outputs_[1].crtc, 0, 0, kFirstMode + 3, | |
1384 outputs_[1].output).c_str(), | |
1385 // Since it was requested to go into mirror mode | |
1386 // and the configured modes were different, it | |
1387 // should now try and setup a valid configurable | |
1388 // extended mode. | |
1389 GetFramebufferAction( | |
1390 outputs_[0].mode_infos[kFirstMode].width, | |
1391 outputs_[0].mode_infos[kFirstMode].height + | |
1392 outputs_[1].mode_infos[kFirstMode].height + | |
1393 OutputConfigurator::kVerticalGap, | |
1394 outputs_[0].crtc, outputs_[1].crtc).c_str(), | |
1395 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode, | |
1396 outputs_[0].output).c_str(), | |
1397 GetCrtcAction(outputs_[0].crtc, 0, 0, kFirstMode + 3, | |
1398 outputs_[0].output).c_str(), | |
1399 GetCrtcAction(outputs_[1].crtc, 0, | |
1400 outputs_[1].mode_infos[kFirstMode].height + | |
1401 OutputConfigurator::kVerticalGap, kFirstMode, | |
1402 outputs_[1].output).c_str(), | |
1403 GetCrtcAction(outputs_[1].crtc, 0, | |
1404 outputs_[1].mode_infos[kFirstMode].height + | |
1405 OutputConfigurator::kVerticalGap, kFirstMode + 3, | |
1406 outputs_[1].output).c_str(), | |
1407 kUngrab, kProjectingOn, NULL), | |
1408 delegate_->GetActionsAndClear()); | |
1409 | |
1410 } | |
1411 | |
1266 } // namespace chromeos | 1412 } // namespace chromeos |
OLD | NEW |