| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "ui/display/chromeos/output_configurator.h" | 5 #include "ui/display/chromeos/output_configurator.h" |
| 6 | 6 |
| 7 #include <X11/Xlib.h> | |
| 8 #include <X11/extensions/Xrandr.h> | |
| 9 | |
| 10 #include "base/bind.h" | 7 #include "base/bind.h" |
| 11 #include "base/logging.h" | 8 #include "base/logging.h" |
| 12 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 14 #include "base/sys_info.h" | 11 #include "base/sys_info.h" |
| 15 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 16 #include "ui/display/chromeos/x11/display_util.h" | 13 #include "ui/display/chromeos/display_mode.h" |
| 14 #include "ui/display/chromeos/display_snapshot.h" |
| 17 #include "ui/display/chromeos/x11/native_display_delegate_x11.h" | 15 #include "ui/display/chromeos/x11/native_display_delegate_x11.h" |
| 18 #include "ui/display/chromeos/x11/touchscreen_delegate_x11.h" | 16 #include "ui/display/chromeos/x11/touchscreen_delegate_x11.h" |
| 19 | 17 |
| 20 namespace ui { | 18 namespace ui { |
| 21 | 19 |
| 22 namespace { | 20 namespace { |
| 23 | 21 |
| 22 typedef std::vector<const DisplayMode*> DisplayModeList; |
| 23 |
| 24 // The delay to perform configuration after RRNotify. See the comment | 24 // The delay to perform configuration after RRNotify. See the comment |
| 25 // in |Dispatch()|. | 25 // in |Dispatch()|. |
| 26 const int64 kConfigureDelayMs = 500; | 26 const int64 kConfigureDelayMs = 500; |
| 27 | 27 |
| 28 // Returns a string describing |state|. | 28 // Returns a string describing |state|. |
| 29 std::string DisplayPowerStateToString(chromeos::DisplayPowerState state) { | 29 std::string DisplayPowerStateToString(chromeos::DisplayPowerState state) { |
| 30 switch (state) { | 30 switch (state) { |
| 31 case chromeos::DISPLAY_POWER_ALL_ON: | 31 case chromeos::DISPLAY_POWER_ALL_ON: |
| 32 return "ALL_ON"; | 32 return "ALL_ON"; |
| 33 case chromeos::DISPLAY_POWER_ALL_OFF: | 33 case chromeos::DISPLAY_POWER_ALL_OFF: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 52 return "SINGLE"; | 52 return "SINGLE"; |
| 53 case OUTPUT_STATE_DUAL_MIRROR: | 53 case OUTPUT_STATE_DUAL_MIRROR: |
| 54 return "DUAL_MIRROR"; | 54 return "DUAL_MIRROR"; |
| 55 case OUTPUT_STATE_DUAL_EXTENDED: | 55 case OUTPUT_STATE_DUAL_EXTENDED: |
| 56 return "DUAL_EXTENDED"; | 56 return "DUAL_EXTENDED"; |
| 57 } | 57 } |
| 58 NOTREACHED() << "Unknown state " << state; | 58 NOTREACHED() << "Unknown state " << state; |
| 59 return "INVALID"; | 59 return "INVALID"; |
| 60 } | 60 } |
| 61 | 61 |
| 62 // Returns a string representation of OutputSnapshot. | 62 // Returns a string representation of DisplayMode. |
| 63 std::string OutputSnapshotToString( | 63 // TODO(dnicoara) Move this to DisplayMode. |
| 64 const OutputConfigurator::OutputSnapshot* output) { | 64 std::string DisplayModeToString(const DisplayMode* mode) { |
| 65 return base::StringPrintf( | |
| 66 "[type=%d, output=%ld, crtc=%ld, mode=%ld, dim=%dx%d]", | |
| 67 output->type, | |
| 68 output->output, | |
| 69 output->crtc, | |
| 70 output->current_mode, | |
| 71 static_cast<int>(output->width_mm), | |
| 72 static_cast<int>(output->height_mm)); | |
| 73 } | |
| 74 | |
| 75 // Returns a string representation of ModeInfo. | |
| 76 std::string ModeInfoToString(const OutputConfigurator::ModeInfo* mode) { | |
| 77 return base::StringPrintf("[%dx%d %srate=%f]", | 65 return base::StringPrintf("[%dx%d %srate=%f]", |
| 78 mode->width, | 66 mode->size().width(), |
| 79 mode->height, | 67 mode->size().height(), |
| 80 mode->interlaced ? "interlaced " : "", | 68 mode->is_interlaced() ? "interlaced " : "", |
| 81 mode->refresh_rate); | 69 mode->refresh_rate()); |
| 82 } | 70 } |
| 83 | 71 |
| 84 // Returns the number of outputs in |outputs| that should be turned on, per | 72 // Returns the number of outputs in |outputs| that should be turned on, per |
| 85 // |state|. If |output_power| is non-NULL, it is updated to contain the | 73 // |state|. If |output_power| is non-NULL, it is updated to contain the |
| 86 // on/off state of each corresponding entry in |outputs|. | 74 // on/off state of each corresponding entry in |outputs|. |
| 87 int GetOutputPower( | 75 int GetOutputPower(const std::vector<OutputConfigurator::DisplayState>& outputs, |
| 88 const std::vector<OutputConfigurator::OutputSnapshot>& outputs, | 76 chromeos::DisplayPowerState state, |
| 89 chromeos::DisplayPowerState state, | 77 std::vector<bool>* output_power) { |
| 90 std::vector<bool>* output_power) { | |
| 91 int num_on_outputs = 0; | 78 int num_on_outputs = 0; |
| 92 if (output_power) | 79 if (output_power) |
| 93 output_power->resize(outputs.size()); | 80 output_power->resize(outputs.size()); |
| 94 | 81 |
| 95 for (size_t i = 0; i < outputs.size(); ++i) { | 82 for (size_t i = 0; i < outputs.size(); ++i) { |
| 96 bool internal = outputs[i].type == OUTPUT_TYPE_INTERNAL; | 83 bool internal = outputs[i].display->type() == OUTPUT_TYPE_INTERNAL; |
| 97 bool on = | 84 bool on = |
| 98 state == chromeos::DISPLAY_POWER_ALL_ON || | 85 state == chromeos::DISPLAY_POWER_ALL_ON || |
| 99 (state == chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && | 86 (state == chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && |
| 100 !internal) || | 87 !internal) || |
| 101 (state == chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && internal); | 88 (state == chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && internal); |
| 102 if (output_power) | 89 if (output_power) |
| 103 (*output_power)[i] = on; | 90 (*output_power)[i] = on; |
| 104 if (on) | 91 if (on) |
| 105 num_on_outputs++; | 92 num_on_outputs++; |
| 106 } | 93 } |
| 107 return num_on_outputs; | 94 return num_on_outputs; |
| 108 } | 95 } |
| 109 | 96 |
| 110 } // namespace | 97 } // namespace |
| 111 | 98 |
| 112 OutputConfigurator::ModeInfo::ModeInfo() | |
| 113 : width(0), | |
| 114 height(0), | |
| 115 interlaced(false), | |
| 116 refresh_rate(0.0) {} | |
| 117 | |
| 118 OutputConfigurator::ModeInfo::ModeInfo(int width, | |
| 119 int height, | |
| 120 bool interlaced, | |
| 121 float refresh_rate) | |
| 122 : width(width), | |
| 123 height(height), | |
| 124 interlaced(interlaced), | |
| 125 refresh_rate(refresh_rate) {} | |
| 126 | |
| 127 OutputConfigurator::CoordinateTransformation::CoordinateTransformation() | 99 OutputConfigurator::CoordinateTransformation::CoordinateTransformation() |
| 128 : x_scale(1.0), | 100 : x_scale(1.0), |
| 129 x_offset(0.0), | 101 x_offset(0.0), |
| 130 y_scale(1.0), | 102 y_scale(1.0), |
| 131 y_offset(0.0) {} | 103 y_offset(0.0) {} |
| 132 | 104 |
| 133 OutputConfigurator::OutputSnapshot::OutputSnapshot() | 105 OutputConfigurator::DisplayState::DisplayState() |
| 134 : output(None), | 106 : display(NULL), |
| 135 crtc(None), | |
| 136 current_mode(None), | |
| 137 native_mode(None), | |
| 138 mirror_mode(None), | |
| 139 selected_mode(None), | |
| 140 x(0), | |
| 141 y(0), | |
| 142 width_mm(0), | |
| 143 height_mm(0), | |
| 144 is_aspect_preserving_scaling(false), | |
| 145 type(OUTPUT_TYPE_UNKNOWN), | |
| 146 touch_device_id(0), | 107 touch_device_id(0), |
| 147 display_id(0), | 108 selected_mode(NULL), |
| 148 has_display_id(false), | 109 mirror_mode(NULL) {} |
| 149 index(0) {} | |
| 150 | |
| 151 OutputConfigurator::OutputSnapshot::~OutputSnapshot() {} | |
| 152 | 110 |
| 153 bool OutputConfigurator::TestApi::TriggerConfigureTimeout() { | 111 bool OutputConfigurator::TestApi::TriggerConfigureTimeout() { |
| 154 if (configurator_->configure_timer_.get() && | 112 if (configurator_->configure_timer_.get() && |
| 155 configurator_->configure_timer_->IsRunning()) { | 113 configurator_->configure_timer_->IsRunning()) { |
| 156 configurator_->configure_timer_.reset(); | 114 configurator_->configure_timer_.reset(); |
| 157 configurator_->ConfigureOutputs(); | 115 configurator_->ConfigureOutputs(); |
| 158 return true; | 116 return true; |
| 159 } else { | 117 } else { |
| 160 return false; | 118 return false; |
| 161 } | 119 } |
| 162 } | 120 } |
| 163 | 121 |
| 164 // static | 122 // static |
| 165 const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo( | 123 const DisplayMode* OutputConfigurator::FindDisplayModeMatchingSize( |
| 166 const OutputSnapshot& output, | 124 const DisplaySnapshot& output, |
| 167 RRMode mode) { | 125 const gfx::Size& size) { |
| 168 if (mode == None) | 126 const DisplayMode* best_mode = NULL; |
| 169 return NULL; | 127 for (DisplayModeList::const_iterator it = output.modes().begin(); |
| 128 it != output.modes().end(); |
| 129 ++it) { |
| 130 const DisplayMode* mode = *it; |
| 170 | 131 |
| 171 ModeInfoMap::const_iterator it = output.mode_infos.find(mode); | 132 if (mode->size() != size) |
| 172 if (it == output.mode_infos.end()) { | 133 continue; |
| 173 LOG(WARNING) << "Unable to find info about mode " << mode << " for output " | 134 |
| 174 << output.output; | 135 if (!best_mode) { |
| 175 return NULL; | 136 best_mode = mode; |
| 137 continue; |
| 138 } |
| 139 |
| 140 if (mode->is_interlaced()) { |
| 141 if (!best_mode->is_interlaced()) |
| 142 continue; |
| 143 } else { |
| 144 // Reset the best rate if the non interlaced is |
| 145 // found the first time. |
| 146 if (best_mode->is_interlaced()) { |
| 147 best_mode = mode; |
| 148 continue; |
| 149 } |
| 150 } |
| 151 if (mode->refresh_rate() < best_mode->refresh_rate()) |
| 152 continue; |
| 153 |
| 154 best_mode = mode; |
| 176 } | 155 } |
| 177 return &it->second; | |
| 178 } | |
| 179 | 156 |
| 180 // static | 157 return best_mode; |
| 181 RRMode OutputConfigurator::FindOutputModeMatchingSize( | |
| 182 const OutputSnapshot& output, | |
| 183 int width, | |
| 184 int height) { | |
| 185 RRMode found = None; | |
| 186 float best_rate = 0; | |
| 187 bool non_interlaced_found = false; | |
| 188 for (ModeInfoMap::const_iterator it = output.mode_infos.begin(); | |
| 189 it != output.mode_infos.end(); | |
| 190 ++it) { | |
| 191 RRMode mode = it->first; | |
| 192 const ModeInfo& info = it->second; | |
| 193 | |
| 194 if (info.width == width && info.height == height) { | |
| 195 if (info.interlaced) { | |
| 196 if (non_interlaced_found) | |
| 197 continue; | |
| 198 } else { | |
| 199 // Reset the best rate if the non interlaced is | |
| 200 // found the first time. | |
| 201 if (!non_interlaced_found) | |
| 202 best_rate = info.refresh_rate; | |
| 203 non_interlaced_found = true; | |
| 204 } | |
| 205 if (info.refresh_rate < best_rate) | |
| 206 continue; | |
| 207 | |
| 208 found = mode; | |
| 209 best_rate = info.refresh_rate; | |
| 210 } | |
| 211 } | |
| 212 return found; | |
| 213 } | 158 } |
| 214 | 159 |
| 215 OutputConfigurator::OutputConfigurator() | 160 OutputConfigurator::OutputConfigurator() |
| 216 : state_controller_(NULL), | 161 : state_controller_(NULL), |
| 217 mirroring_controller_(NULL), | 162 mirroring_controller_(NULL), |
| 218 is_panel_fitting_enabled_(false), | 163 is_panel_fitting_enabled_(false), |
| 219 configure_display_(base::SysInfo::IsRunningOnChromeOS()), | 164 configure_display_(base::SysInfo::IsRunningOnChromeOS()), |
| 220 output_state_(OUTPUT_STATE_INVALID), | 165 output_state_(OUTPUT_STATE_INVALID), |
| 221 power_state_(chromeos::DISPLAY_POWER_ALL_ON), | 166 power_state_(chromeos::DISPLAY_POWER_ALL_ON), |
| 222 next_output_protection_client_id_(1) {} | 167 next_output_protection_client_id_(1) {} |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 EnterStateOrFallBackToSoftwareMirroring(new_state, power_state_); | 222 EnterStateOrFallBackToSoftwareMirroring(new_state, power_state_); |
| 278 | 223 |
| 279 // Force the DPMS on chrome startup as the driver doesn't always detect | 224 // Force the DPMS on chrome startup as the driver doesn't always detect |
| 280 // that all displays are on when signing out. | 225 // that all displays are on when signing out. |
| 281 native_display_delegate_->ForceDPMSOn(); | 226 native_display_delegate_->ForceDPMSOn(); |
| 282 native_display_delegate_->UngrabServer(); | 227 native_display_delegate_->UngrabServer(); |
| 283 NotifyObservers(success, new_state); | 228 NotifyObservers(success, new_state); |
| 284 } | 229 } |
| 285 | 230 |
| 286 bool OutputConfigurator::ApplyProtections(const DisplayProtections& requests) { | 231 bool OutputConfigurator::ApplyProtections(const DisplayProtections& requests) { |
| 287 for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); | 232 for (DisplayStateList::const_iterator it = cached_outputs_.begin(); |
| 288 it != cached_outputs_.end(); | 233 it != cached_outputs_.end(); |
| 289 ++it) { | 234 ++it) { |
| 290 uint32_t all_desired = 0; | 235 uint32_t all_desired = 0; |
| 291 DisplayProtections::const_iterator request_it = | 236 DisplayProtections::const_iterator request_it = |
| 292 requests.find(it->display_id); | 237 requests.find(it->display->display_id()); |
| 293 if (request_it != requests.end()) | 238 if (request_it != requests.end()) |
| 294 all_desired = request_it->second; | 239 all_desired = request_it->second; |
| 295 switch (it->type) { | 240 switch (it->display->type()) { |
| 296 case OUTPUT_TYPE_UNKNOWN: | 241 case OUTPUT_TYPE_UNKNOWN: |
| 297 return false; | 242 return false; |
| 298 // DisplayPort, DVI, and HDMI all support HDCP. | 243 // DisplayPort, DVI, and HDMI all support HDCP. |
| 299 case OUTPUT_TYPE_DISPLAYPORT: | 244 case OUTPUT_TYPE_DISPLAYPORT: |
| 300 case OUTPUT_TYPE_DVI: | 245 case OUTPUT_TYPE_DVI: |
| 301 case OUTPUT_TYPE_HDMI: { | 246 case OUTPUT_TYPE_HDMI: { |
| 302 HDCPState new_desired_state = | 247 HDCPState new_desired_state = |
| 303 (all_desired & OUTPUT_PROTECTION_METHOD_HDCP) ? | 248 (all_desired & OUTPUT_PROTECTION_METHOD_HDCP) ? |
| 304 HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED; | 249 HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED; |
| 305 if (!native_display_delegate_->SetHDCPState(*it, new_desired_state)) | 250 if (!native_display_delegate_->SetHDCPState(*it->display, |
| 251 new_desired_state)) |
| 306 return false; | 252 return false; |
| 307 break; | 253 break; |
| 308 } | 254 } |
| 309 case OUTPUT_TYPE_INTERNAL: | 255 case OUTPUT_TYPE_INTERNAL: |
| 310 case OUTPUT_TYPE_VGA: | 256 case OUTPUT_TYPE_VGA: |
| 311 case OUTPUT_TYPE_NETWORK: | 257 case OUTPUT_TYPE_NETWORK: |
| 312 // No protections for these types. Do nothing. | 258 // No protections for these types. Do nothing. |
| 313 break; | 259 break; |
| 314 case OUTPUT_TYPE_NONE: | 260 case OUTPUT_TYPE_NONE: |
| 315 NOTREACHED(); | 261 NOTREACHED(); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 OutputProtectionClientId client_id, | 297 OutputProtectionClientId client_id, |
| 352 int64 display_id, | 298 int64 display_id, |
| 353 uint32_t* link_mask, | 299 uint32_t* link_mask, |
| 354 uint32_t* protection_mask) { | 300 uint32_t* protection_mask) { |
| 355 if (!configure_display_) | 301 if (!configure_display_) |
| 356 return false; | 302 return false; |
| 357 | 303 |
| 358 uint32_t enabled = 0; | 304 uint32_t enabled = 0; |
| 359 uint32_t unfulfilled = 0; | 305 uint32_t unfulfilled = 0; |
| 360 *link_mask = 0; | 306 *link_mask = 0; |
| 361 for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); | 307 for (DisplayStateList::const_iterator it = cached_outputs_.begin(); |
| 362 it != cached_outputs_.end(); | 308 it != cached_outputs_.end(); |
| 363 ++it) { | 309 ++it) { |
| 364 if (it->display_id != display_id) | 310 if (it->display->display_id() != display_id) |
| 365 continue; | 311 continue; |
| 366 *link_mask |= it->type; | 312 *link_mask |= it->display->type(); |
| 367 switch (it->type) { | 313 switch (it->display->type()) { |
| 368 case OUTPUT_TYPE_UNKNOWN: | 314 case OUTPUT_TYPE_UNKNOWN: |
| 369 return false; | 315 return false; |
| 370 // DisplayPort, DVI, and HDMI all support HDCP. | 316 // DisplayPort, DVI, and HDMI all support HDCP. |
| 371 case OUTPUT_TYPE_DISPLAYPORT: | 317 case OUTPUT_TYPE_DISPLAYPORT: |
| 372 case OUTPUT_TYPE_DVI: | 318 case OUTPUT_TYPE_DVI: |
| 373 case OUTPUT_TYPE_HDMI: { | 319 case OUTPUT_TYPE_HDMI: { |
| 374 HDCPState state; | 320 HDCPState state; |
| 375 if (!native_display_delegate_->GetHDCPState(*it, &state)) | 321 if (!native_display_delegate_->GetHDCPState(*it->display, &state)) |
| 376 return false; | 322 return false; |
| 377 if (state == HDCP_STATE_ENABLED) | 323 if (state == HDCP_STATE_ENABLED) |
| 378 enabled |= OUTPUT_PROTECTION_METHOD_HDCP; | 324 enabled |= OUTPUT_PROTECTION_METHOD_HDCP; |
| 379 else | 325 else |
| 380 unfulfilled |= OUTPUT_PROTECTION_METHOD_HDCP; | 326 unfulfilled |= OUTPUT_PROTECTION_METHOD_HDCP; |
| 381 break; | 327 break; |
| 382 } | 328 } |
| 383 case OUTPUT_TYPE_INTERNAL: | 329 case OUTPUT_TYPE_INTERNAL: |
| 384 case OUTPUT_TYPE_VGA: | 330 case OUTPUT_TYPE_VGA: |
| 385 case OUTPUT_TYPE_NETWORK: | 331 case OUTPUT_TYPE_NETWORK: |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 UpdateCachedOutputs(); | 411 UpdateCachedOutputs(); |
| 466 | 412 |
| 467 const OutputState new_state = ChooseOutputState(power_state); | 413 const OutputState new_state = ChooseOutputState(power_state); |
| 468 bool attempted_change = false; | 414 bool attempted_change = false; |
| 469 bool success = false; | 415 bool success = false; |
| 470 | 416 |
| 471 bool only_if_single_internal_display = | 417 bool only_if_single_internal_display = |
| 472 flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; | 418 flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; |
| 473 bool single_internal_display = | 419 bool single_internal_display = |
| 474 cached_outputs_.size() == 1 && | 420 cached_outputs_.size() == 1 && |
| 475 cached_outputs_[0].type == OUTPUT_TYPE_INTERNAL; | 421 cached_outputs_[0].display->type() == OUTPUT_TYPE_INTERNAL; |
| 476 if (single_internal_display || !only_if_single_internal_display) { | 422 if (single_internal_display || !only_if_single_internal_display) { |
| 477 success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state); | 423 success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state); |
| 478 attempted_change = true; | 424 attempted_change = true; |
| 479 | 425 |
| 480 // Force the DPMS on since the driver doesn't always detect that it | 426 // Force the DPMS on since the driver doesn't always detect that it |
| 481 // should turn on. This is needed when coming back from idle suspend. | 427 // should turn on. This is needed when coming back from idle suspend. |
| 482 if (success && power_state != chromeos::DISPLAY_POWER_ALL_OFF) | 428 if (success && power_state != chromeos::DISPLAY_POWER_ALL_OFF) |
| 483 native_display_delegate_->ForceDPMSOn(); | 429 native_display_delegate_->ForceDPMSOn(); |
| 484 } | 430 } |
| 485 | 431 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 } | 499 } |
| 554 } | 500 } |
| 555 | 501 |
| 556 void OutputConfigurator::ResumeDisplays() { | 502 void OutputConfigurator::ResumeDisplays() { |
| 557 // Force probing to ensure that we pick up any changes that were made | 503 // Force probing to ensure that we pick up any changes that were made |
| 558 // while the system was suspended. | 504 // while the system was suspended. |
| 559 SetDisplayPower(power_state_, kSetDisplayPowerForceProbe); | 505 SetDisplayPower(power_state_, kSetDisplayPowerForceProbe); |
| 560 } | 506 } |
| 561 | 507 |
| 562 void OutputConfigurator::UpdateCachedOutputs() { | 508 void OutputConfigurator::UpdateCachedOutputs() { |
| 563 cached_outputs_ = native_display_delegate_->GetOutputs(); | 509 std::vector<DisplaySnapshot*> snapshots = |
| 510 native_display_delegate_->GetOutputs(); |
| 511 |
| 512 cached_outputs_.clear(); |
| 513 for (size_t i = 0; i < snapshots.size(); ++i) { |
| 514 DisplayState display_state; |
| 515 display_state.display = snapshots[i]; |
| 516 cached_outputs_.push_back(display_state); |
| 517 } |
| 518 |
| 564 touchscreen_delegate_->AssociateTouchscreens(&cached_outputs_); | 519 touchscreen_delegate_->AssociateTouchscreens(&cached_outputs_); |
| 565 | 520 |
| 566 // Set |selected_mode| fields. | 521 // Set |selected_mode| fields. |
| 567 for (size_t i = 0; i < cached_outputs_.size(); ++i) { | 522 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 568 OutputSnapshot* output = &cached_outputs_[i]; | 523 DisplayState* output = &cached_outputs_[i]; |
| 569 if (output->has_display_id) { | 524 if (output->display->has_proper_display_id()) { |
| 570 int width = 0, height = 0; | 525 gfx::Size size; |
| 571 if (state_controller_ && state_controller_->GetResolutionForDisplayId( | 526 if (state_controller_ && state_controller_->GetResolutionForDisplayId( |
| 572 output->display_id, &width, &height)) { | 527 output->display->display_id(), &size)) { |
| 573 output->selected_mode = | 528 output->selected_mode = |
| 574 FindOutputModeMatchingSize(*output, width, height); | 529 FindDisplayModeMatchingSize(*output->display, size); |
| 575 } | 530 } |
| 576 } | 531 } |
| 577 // Fall back to native mode. | 532 // Fall back to native mode. |
| 578 if (output->selected_mode == None) | 533 if (!output->selected_mode) |
| 579 output->selected_mode = output->native_mode; | 534 output->selected_mode = output->display->native_mode(); |
| 580 } | 535 } |
| 581 | 536 |
| 582 // Set |mirror_mode| fields. | 537 // Set |mirror_mode| fields. |
| 583 if (cached_outputs_.size() == 2) { | 538 if (cached_outputs_.size() == 2) { |
| 584 bool one_is_internal = cached_outputs_[0].type == OUTPUT_TYPE_INTERNAL; | 539 bool one_is_internal = |
| 585 bool two_is_internal = cached_outputs_[1].type == OUTPUT_TYPE_INTERNAL; | 540 cached_outputs_[0].display->type() == OUTPUT_TYPE_INTERNAL; |
| 541 bool two_is_internal = |
| 542 cached_outputs_[1].display->type() == OUTPUT_TYPE_INTERNAL; |
| 586 int internal_outputs = | 543 int internal_outputs = |
| 587 (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0); | 544 (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0); |
| 588 DCHECK_LT(internal_outputs, 2); | 545 DCHECK_LT(internal_outputs, 2); |
| 589 LOG_IF(WARNING, internal_outputs == 2) << "Two internal outputs detected."; | 546 LOG_IF(WARNING, internal_outputs == 2) << "Two internal outputs detected."; |
| 590 | 547 |
| 591 bool can_mirror = false; | 548 bool can_mirror = false; |
| 592 for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) { | 549 for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) { |
| 593 // Try preserving external output's aspect ratio on the first attempt. | 550 // Try preserving external output's aspect ratio on the first attempt. |
| 594 // If that fails, fall back to the highest matching resolution. | 551 // If that fails, fall back to the highest matching resolution. |
| 595 bool preserve_aspect = attempt == 0; | 552 bool preserve_aspect = attempt == 0; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 617 // it will succeed with the other. This way we will have the correct | 574 // it will succeed with the other. This way we will have the correct |
| 618 // aspect ratio on at least one of them. | 575 // aspect ratio on at least one of them. |
| 619 can_mirror = FindMirrorMode( | 576 can_mirror = FindMirrorMode( |
| 620 &cached_outputs_[1], &cached_outputs_[0], false, preserve_aspect); | 577 &cached_outputs_[1], &cached_outputs_[0], false, preserve_aspect); |
| 621 } | 578 } |
| 622 } | 579 } |
| 623 } | 580 } |
| 624 } | 581 } |
| 625 } | 582 } |
| 626 | 583 |
| 627 bool OutputConfigurator::FindMirrorMode(OutputSnapshot* internal_output, | 584 bool OutputConfigurator::FindMirrorMode(DisplayState* internal_output, |
| 628 OutputSnapshot* external_output, | 585 DisplayState* external_output, |
| 629 bool try_panel_fitting, | 586 bool try_panel_fitting, |
| 630 bool preserve_aspect) { | 587 bool preserve_aspect) { |
| 631 const ModeInfo* internal_native_info = | 588 const DisplayMode* internal_native_info = |
| 632 GetModeInfo(*internal_output, internal_output->native_mode); | 589 internal_output->display->native_mode(); |
| 633 const ModeInfo* external_native_info = | 590 const DisplayMode* external_native_info = |
| 634 GetModeInfo(*external_output, external_output->native_mode); | 591 external_output->display->native_mode(); |
| 635 if (!internal_native_info || !external_native_info) | 592 if (!internal_native_info || !external_native_info) |
| 636 return false; | 593 return false; |
| 637 | 594 |
| 638 // Check if some external output resolution can be mirrored on internal. | 595 // Check if some external output resolution can be mirrored on internal. |
| 639 // Prefer the modes in the order that X sorts them, assuming this is the order | 596 // Prefer the modes in the order that X sorts them, assuming this is the order |
| 640 // in which they look better on the monitor. | 597 // in which they look better on the monitor. |
| 641 for (ModeInfoMap::const_iterator external_it = | 598 for (DisplayModeList::const_iterator external_it = |
| 642 external_output->mode_infos.begin(); | 599 external_output->display->modes().begin(); |
| 643 external_it != external_output->mode_infos.end(); | 600 external_it != external_output->display->modes().end(); |
| 644 ++external_it) { | 601 ++external_it) { |
| 645 const ModeInfo& external_info = external_it->second; | 602 const DisplayMode& external_info = **external_it; |
| 646 bool is_native_aspect_ratio = | 603 bool is_native_aspect_ratio = |
| 647 external_native_info->width * external_info.height == | 604 external_native_info->size().width() * external_info.size().height() == |
| 648 external_native_info->height * external_info.width; | 605 external_native_info->size().height() * external_info.size().width(); |
| 649 if (preserve_aspect && !is_native_aspect_ratio) | 606 if (preserve_aspect && !is_native_aspect_ratio) |
| 650 continue; // Allow only aspect ratio preserving modes for mirroring. | 607 continue; // Allow only aspect ratio preserving modes for mirroring. |
| 651 | 608 |
| 652 // Try finding an exact match. | 609 // Try finding an exact match. |
| 653 for (ModeInfoMap::const_iterator internal_it = | 610 for (DisplayModeList::const_iterator internal_it = |
| 654 internal_output->mode_infos.begin(); | 611 internal_output->display->modes().begin(); |
| 655 internal_it != internal_output->mode_infos.end(); | 612 internal_it != internal_output->display->modes().end(); |
| 656 ++internal_it) { | 613 ++internal_it) { |
| 657 const ModeInfo& internal_info = internal_it->second; | 614 const DisplayMode& internal_info = **internal_it; |
| 658 if (internal_info.width == external_info.width && | 615 if (internal_info.size().width() == external_info.size().width() && |
| 659 internal_info.height == external_info.height && | 616 internal_info.size().height() == external_info.size().height() && |
| 660 internal_info.interlaced == external_info.interlaced) { | 617 internal_info.is_interlaced() == external_info.is_interlaced()) { |
| 661 internal_output->mirror_mode = internal_it->first; | 618 internal_output->mirror_mode = *internal_it; |
| 662 external_output->mirror_mode = external_it->first; | 619 external_output->mirror_mode = *external_it; |
| 663 return true; // Mirror mode found. | 620 return true; // Mirror mode found. |
| 664 } | 621 } |
| 665 } | 622 } |
| 666 | 623 |
| 667 // Try to create a matching internal output mode by panel fitting. | 624 // Try to create a matching internal output mode by panel fitting. |
| 668 if (try_panel_fitting) { | 625 if (try_panel_fitting) { |
| 669 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks | 626 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks |
| 670 // ugly, so, can fit == can upscale. Also, internal panels don't support | 627 // ugly, so, can fit == can upscale. Also, internal panels don't support |
| 671 // fitting interlaced modes. | 628 // fitting interlaced modes. |
| 672 bool can_fit = internal_native_info->width >= external_info.width && | 629 bool can_fit = internal_native_info->size().width() >= |
| 673 internal_native_info->height >= external_info.height && | 630 external_info.size().width() && |
| 674 !external_info.interlaced; | 631 internal_native_info->size().height() >= |
| 632 external_info.size().height() && |
| 633 !external_info.is_interlaced(); |
| 675 if (can_fit) { | 634 if (can_fit) { |
| 676 RRMode mode = external_it->first; | 635 native_display_delegate_->AddMode(*internal_output->display, |
| 677 native_display_delegate_->AddMode(*internal_output, mode); | 636 *external_it); |
| 678 internal_output->mode_infos.insert(std::make_pair(mode, external_info)); | 637 internal_output->display->add_mode(*external_it); |
| 679 internal_output->mirror_mode = mode; | 638 internal_output->mirror_mode = *external_it; |
| 680 external_output->mirror_mode = mode; | 639 external_output->mirror_mode = *external_it; |
| 681 return true; // Mirror mode created. | 640 return true; // Mirror mode created. |
| 682 } | 641 } |
| 683 } | 642 } |
| 684 } | 643 } |
| 685 | 644 |
| 686 return false; | 645 return false; |
| 687 } | 646 } |
| 688 | 647 |
| 689 void OutputConfigurator::ConfigureOutputs() { | 648 void OutputConfigurator::ConfigureOutputs() { |
| 690 configure_timer_.reset(); | 649 configure_timer_.reset(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 733 | 692 |
| 734 bool OutputConfigurator::EnterState(OutputState output_state, | 693 bool OutputConfigurator::EnterState(OutputState output_state, |
| 735 chromeos::DisplayPowerState power_state) { | 694 chromeos::DisplayPowerState power_state) { |
| 736 std::vector<bool> output_power; | 695 std::vector<bool> output_power; |
| 737 int num_on_outputs = | 696 int num_on_outputs = |
| 738 GetOutputPower(cached_outputs_, power_state, &output_power); | 697 GetOutputPower(cached_outputs_, power_state, &output_power); |
| 739 VLOG(1) << "EnterState: output=" << OutputStateToString(output_state) | 698 VLOG(1) << "EnterState: output=" << OutputStateToString(output_state) |
| 740 << " power=" << DisplayPowerStateToString(power_state); | 699 << " power=" << DisplayPowerStateToString(power_state); |
| 741 | 700 |
| 742 // Framebuffer dimensions. | 701 // Framebuffer dimensions. |
| 743 int width = 0, height = 0; | 702 gfx::Size size; |
| 744 std::vector<OutputSnapshot> updated_outputs = cached_outputs_; | 703 |
| 704 std::vector<gfx::Point> new_origins(cached_outputs_.size(), gfx::Point()); |
| 705 std::vector<const DisplayMode*> new_mode; |
| 706 for (size_t i = 0; i < cached_outputs_.size(); ++i) |
| 707 new_mode.push_back(cached_outputs_[i].display->current_mode()); |
| 745 | 708 |
| 746 switch (output_state) { | 709 switch (output_state) { |
| 747 case OUTPUT_STATE_INVALID: | 710 case OUTPUT_STATE_INVALID: |
| 748 NOTREACHED() << "Ignoring request to enter invalid state with " | 711 NOTREACHED() << "Ignoring request to enter invalid state with " |
| 749 << updated_outputs.size() << " connected output(s)"; | 712 << cached_outputs_.size() << " connected output(s)"; |
| 750 return false; | 713 return false; |
| 751 case OUTPUT_STATE_HEADLESS: | 714 case OUTPUT_STATE_HEADLESS: |
| 752 if (updated_outputs.size() != 0) { | 715 if (cached_outputs_.size() != 0) { |
| 753 LOG(WARNING) << "Ignoring request to enter headless mode with " | 716 LOG(WARNING) << "Ignoring request to enter headless mode with " |
| 754 << updated_outputs.size() << " connected output(s)"; | 717 << cached_outputs_.size() << " connected output(s)"; |
| 755 return false; | 718 return false; |
| 756 } | 719 } |
| 757 break; | 720 break; |
| 758 case OUTPUT_STATE_SINGLE: { | 721 case OUTPUT_STATE_SINGLE: { |
| 759 // If there are multiple outputs connected, only one should be turned on. | 722 // If there are multiple outputs connected, only one should be turned on. |
| 760 if (updated_outputs.size() != 1 && num_on_outputs != 1) { | 723 if (cached_outputs_.size() != 1 && num_on_outputs != 1) { |
| 761 LOG(WARNING) << "Ignoring request to enter single mode with " | 724 LOG(WARNING) << "Ignoring request to enter single mode with " |
| 762 << updated_outputs.size() << " connected outputs and " | 725 << cached_outputs_.size() << " connected outputs and " |
| 763 << num_on_outputs << " turned on"; | 726 << num_on_outputs << " turned on"; |
| 764 return false; | 727 return false; |
| 765 } | 728 } |
| 766 | 729 |
| 767 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 730 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 768 OutputSnapshot* output = &updated_outputs[i]; | 731 DisplayState* output = &cached_outputs_[i]; |
| 769 output->x = 0; | 732 new_mode[i] = output_power[i] ? output->selected_mode : NULL; |
| 770 output->y = 0; | |
| 771 output->current_mode = output_power[i] ? output->selected_mode : None; | |
| 772 | 733 |
| 773 if (output_power[i] || updated_outputs.size() == 1) { | 734 if (output_power[i] || cached_outputs_.size() == 1) { |
| 774 const ModeInfo* mode_info = | 735 const DisplayMode* mode_info = output->selected_mode; |
| 775 GetModeInfo(*output, output->selected_mode); | |
| 776 if (!mode_info) | 736 if (!mode_info) |
| 777 return false; | 737 return false; |
| 778 if (mode_info->width == 1024 && mode_info->height == 768) { | 738 if (mode_info->size() == gfx::Size(1024, 768)) { |
| 779 VLOG(1) << "Potentially misdetecting display(1024x768):" | 739 VLOG(1) << "Potentially misdetecting display(1024x768):" |
| 780 << " outputs size=" << updated_outputs.size() | 740 << " outputs size=" << cached_outputs_.size() |
| 781 << ", num_on_outputs=" << num_on_outputs | 741 << ", num_on_outputs=" << num_on_outputs |
| 782 << ", current size:" << width << "x" << height | 742 << ", current size:" << size.width() << "x" << size.height() |
| 783 << ", i=" << i | 743 << ", i=" << i << ", output=" << output->display->ToString() |
| 784 << ", output=" << OutputSnapshotToString(output) | 744 << ", display_mode=" << DisplayModeToString(mode_info); |
| 785 << ", mode_info=" << ModeInfoToString(mode_info); | |
| 786 } | 745 } |
| 787 width = mode_info->width; | 746 size = mode_info->size(); |
| 788 height = mode_info->height; | |
| 789 } | 747 } |
| 790 } | 748 } |
| 791 break; | 749 break; |
| 792 } | 750 } |
| 793 case OUTPUT_STATE_DUAL_MIRROR: { | 751 case OUTPUT_STATE_DUAL_MIRROR: { |
| 794 if (updated_outputs.size() != 2 || | 752 if (cached_outputs_.size() != 2 || |
| 795 (num_on_outputs != 0 && num_on_outputs != 2)) { | 753 (num_on_outputs != 0 && num_on_outputs != 2)) { |
| 796 LOG(WARNING) << "Ignoring request to enter mirrored mode with " | 754 LOG(WARNING) << "Ignoring request to enter mirrored mode with " |
| 797 << updated_outputs.size() << " connected output(s) and " | 755 << cached_outputs_.size() << " connected output(s) and " |
| 798 << num_on_outputs << " turned on"; | 756 << num_on_outputs << " turned on"; |
| 799 return false; | 757 return false; |
| 800 } | 758 } |
| 801 | 759 |
| 802 if (!updated_outputs[0].mirror_mode) | 760 const DisplayMode* mode_info = cached_outputs_[0].mirror_mode; |
| 803 return false; | |
| 804 const ModeInfo* mode_info = | |
| 805 GetModeInfo(updated_outputs[0], updated_outputs[0].mirror_mode); | |
| 806 if (!mode_info) | 761 if (!mode_info) |
| 807 return false; | 762 return false; |
| 808 width = mode_info->width; | 763 size = mode_info->size(); |
| 809 height = mode_info->height; | |
| 810 | 764 |
| 811 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 765 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 812 OutputSnapshot* output = &updated_outputs[i]; | 766 DisplayState* output = &cached_outputs_[i]; |
| 813 output->x = 0; | 767 new_mode[i] = output_power[i] ? output->mirror_mode : NULL; |
| 814 output->y = 0; | |
| 815 output->current_mode = output_power[i] ? output->mirror_mode : None; | |
| 816 if (output->touch_device_id) { | 768 if (output->touch_device_id) { |
| 817 // CTM needs to be calculated if aspect preserving scaling is used. | 769 // CTM needs to be calculated if aspect preserving scaling is used. |
| 818 // Otherwise, assume it is full screen, and use identity CTM. | 770 // Otherwise, assume it is full screen, and use identity CTM. |
| 819 if (output->mirror_mode != output->native_mode && | 771 if (output->mirror_mode != output->display->native_mode() && |
| 820 output->is_aspect_preserving_scaling) { | 772 output->display->is_aspect_preserving_scaling()) { |
| 821 output->transform = GetMirrorModeCTM(*output); | 773 output->transform = GetMirrorModeCTM(*output); |
| 822 mirrored_display_area_ratio_map_[output->touch_device_id] = | 774 mirrored_display_area_ratio_map_[output->touch_device_id] = |
| 823 GetMirroredDisplayAreaRatio(*output); | 775 GetMirroredDisplayAreaRatio(*output); |
| 824 } | 776 } |
| 825 } | 777 } |
| 826 } | 778 } |
| 827 break; | 779 break; |
| 828 } | 780 } |
| 829 case OUTPUT_STATE_DUAL_EXTENDED: { | 781 case OUTPUT_STATE_DUAL_EXTENDED: { |
| 830 if (updated_outputs.size() != 2 || | 782 if (cached_outputs_.size() != 2 || |
| 831 (num_on_outputs != 0 && num_on_outputs != 2)) { | 783 (num_on_outputs != 0 && num_on_outputs != 2)) { |
| 832 LOG(WARNING) << "Ignoring request to enter extended mode with " | 784 LOG(WARNING) << "Ignoring request to enter extended mode with " |
| 833 << updated_outputs.size() << " connected output(s) and " | 785 << cached_outputs_.size() << " connected output(s) and " |
| 834 << num_on_outputs << " turned on"; | 786 << num_on_outputs << " turned on"; |
| 835 return false; | 787 return false; |
| 836 } | 788 } |
| 837 | 789 |
| 838 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 790 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 839 OutputSnapshot* output = &updated_outputs[i]; | 791 DisplayState* output = &cached_outputs_[i]; |
| 840 output->x = 0; | 792 new_origins[i].set_y(size.height() ? size.height() + kVerticalGap : 0); |
| 841 output->y = height ? height + kVerticalGap : 0; | 793 new_mode[i] = output_power[i] ? output->selected_mode : NULL; |
| 842 output->current_mode = output_power[i] ? output->selected_mode : None; | |
| 843 | 794 |
| 844 // Retain the full screen size even if all outputs are off so the | 795 // Retain the full screen size even if all outputs are off so the |
| 845 // same desktop configuration can be restored when the outputs are | 796 // same desktop configuration can be restored when the outputs are |
| 846 // turned back on. | 797 // turned back on. |
| 847 const ModeInfo* mode_info = | 798 const DisplayMode* mode_info = cached_outputs_[i].selected_mode; |
| 848 GetModeInfo(updated_outputs[i], updated_outputs[i].selected_mode); | |
| 849 if (!mode_info) | 799 if (!mode_info) |
| 850 return false; | 800 return false; |
| 851 width = std::max<int>(width, mode_info->width); | 801 |
| 852 height += (height ? kVerticalGap : 0) + mode_info->height; | 802 size.set_width(std::max<int>(size.width(), mode_info->size().width())); |
| 803 size.set_height(size.height() + (size.height() ? kVerticalGap : 0) + |
| 804 mode_info->size().height()); |
| 853 } | 805 } |
| 854 | 806 |
| 855 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 807 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 856 OutputSnapshot* output = &updated_outputs[i]; | 808 DisplayState* output = &cached_outputs_[i]; |
| 857 if (output->touch_device_id) | 809 if (output->touch_device_id) |
| 858 output->transform = GetExtendedModeCTM(*output, width, height); | 810 output->transform = GetExtendedModeCTM(*output, new_origins[i], size); |
| 859 } | 811 } |
| 860 break; | 812 break; |
| 861 } | 813 } |
| 862 } | 814 } |
| 863 | 815 |
| 864 // Finally, apply the desired changes. | 816 // Finally, apply the desired changes. |
| 865 DCHECK_EQ(cached_outputs_.size(), updated_outputs.size()); | |
| 866 bool all_succeeded = true; | 817 bool all_succeeded = true; |
| 867 if (!updated_outputs.empty()) { | 818 if (!cached_outputs_.empty()) { |
| 868 native_display_delegate_->CreateFrameBuffer(width, height, updated_outputs); | 819 native_display_delegate_->CreateFrameBuffer(size); |
| 869 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 820 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 870 const OutputSnapshot& output = updated_outputs[i]; | 821 const DisplayState& output = cached_outputs_[i]; |
| 871 bool configure_succeeded = false; | 822 bool configure_succeeded = false; |
| 872 | 823 |
| 873 while (true) { | 824 while (true) { |
| 874 if (native_display_delegate_->Configure( | 825 if (native_display_delegate_->Configure( |
| 875 output, output.current_mode, output.x, output.y)) { | 826 *output.display, new_mode[i], new_origins[i])) { |
| 827 output.display->set_current_mode(new_mode[i]); |
| 828 output.display->set_origin(new_origins[i]); |
| 829 |
| 876 configure_succeeded = true; | 830 configure_succeeded = true; |
| 877 break; | 831 break; |
| 878 } | 832 } |
| 879 | 833 |
| 880 LOG(WARNING) << "Unable to configure CRTC " << output.crtc << ":" | 834 const DisplayMode* mode_info = new_mode[i]; |
| 881 << " mode=" << output.current_mode | |
| 882 << " output=" << output.output << " x=" << output.x | |
| 883 << " y=" << output.y; | |
| 884 | |
| 885 const ModeInfo* mode_info = GetModeInfo(output, output.current_mode); | |
| 886 if (!mode_info) | 835 if (!mode_info) |
| 887 break; | 836 break; |
| 888 | 837 |
| 889 // Find the mode with the next-best resolution and see if that can | 838 // Find the mode with the next-best resolution and see if that can |
| 890 // be set. | 839 // be set. |
| 891 int best_mode_pixels = 0; | 840 int best_mode_pixels = 0; |
| 892 | 841 |
| 893 int current_mode_pixels = mode_info->width * mode_info->height; | 842 int current_mode_pixels = mode_info->size().GetArea(); |
| 894 for (ModeInfoMap::const_iterator it = output.mode_infos.begin(); | 843 for (DisplayModeList::const_iterator it = |
| 895 it != output.mode_infos.end(); | 844 output.display->modes().begin(); |
| 845 it != output.display->modes().end(); |
| 896 it++) { | 846 it++) { |
| 897 int pixel_count = it->second.width * it->second.height; | 847 int pixel_count = (*it)->size().GetArea(); |
| 898 if ((pixel_count < current_mode_pixels) && | 848 if ((pixel_count < current_mode_pixels) && |
| 899 (pixel_count > best_mode_pixels)) { | 849 (pixel_count > best_mode_pixels)) { |
| 900 updated_outputs[i].current_mode = it->first; | 850 new_mode[i] = *it; |
| 901 best_mode_pixels = pixel_count; | 851 best_mode_pixels = pixel_count; |
| 902 } | 852 } |
| 903 } | 853 } |
| 904 | 854 |
| 905 if (best_mode_pixels == 0) | 855 if (best_mode_pixels == 0) |
| 906 break; | 856 break; |
| 907 } | 857 } |
| 908 | 858 |
| 909 if (configure_succeeded) { | 859 if (configure_succeeded) { |
| 910 if (output.touch_device_id) | 860 if (output.touch_device_id) |
| 911 touchscreen_delegate_->ConfigureCTM(output.touch_device_id, | 861 touchscreen_delegate_->ConfigureCTM(output.touch_device_id, |
| 912 output.transform); | 862 output.transform); |
| 913 cached_outputs_[i] = updated_outputs[i]; | |
| 914 } else { | 863 } else { |
| 915 all_succeeded = false; | 864 all_succeeded = false; |
| 916 } | 865 } |
| 917 | 866 |
| 918 // If we are trying to set mirror mode and one of the modesets fails, | 867 // If we are trying to set mirror mode and one of the modesets fails, |
| 919 // then the two monitors will be mis-matched. In this case, return | 868 // then the two monitors will be mis-matched. In this case, return |
| 920 // false to let the observers be aware. | 869 // false to let the observers be aware. |
| 921 if (output_state == OUTPUT_STATE_DUAL_MIRROR && output_power[i] && | 870 if (output_state == OUTPUT_STATE_DUAL_MIRROR && output_power[i] && |
| 922 output.current_mode != output.mirror_mode) | 871 output.display->current_mode() != output.mirror_mode) |
| 923 all_succeeded = false; | 872 all_succeeded = false; |
| 924 } | 873 } |
| 925 } | 874 } |
| 926 | 875 |
| 927 if (all_succeeded) { | 876 if (all_succeeded) { |
| 928 output_state_ = output_state; | 877 output_state_ = output_state; |
| 929 power_state_ = power_state; | 878 power_state_ = power_state; |
| 930 } | 879 } |
| 931 return all_succeeded; | 880 return all_succeeded; |
| 932 } | 881 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 943 if (num_on_outputs == 1) { | 892 if (num_on_outputs == 1) { |
| 944 // If only one output is currently turned on, return the "single" | 893 // If only one output is currently turned on, return the "single" |
| 945 // state so that its native mode will be used. | 894 // state so that its native mode will be used. |
| 946 return OUTPUT_STATE_SINGLE; | 895 return OUTPUT_STATE_SINGLE; |
| 947 } else { | 896 } else { |
| 948 // With either both outputs on or both outputs off, use one of the | 897 // With either both outputs on or both outputs off, use one of the |
| 949 // dual modes. | 898 // dual modes. |
| 950 std::vector<int64> display_ids; | 899 std::vector<int64> display_ids; |
| 951 for (size_t i = 0; i < cached_outputs_.size(); ++i) { | 900 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 952 // If display id isn't available, switch to extended mode. | 901 // If display id isn't available, switch to extended mode. |
| 953 if (!cached_outputs_[i].has_display_id) | 902 if (!cached_outputs_[i].display->has_proper_display_id()) |
| 954 return OUTPUT_STATE_DUAL_EXTENDED; | 903 return OUTPUT_STATE_DUAL_EXTENDED; |
| 955 display_ids.push_back(cached_outputs_[i].display_id); | 904 display_ids.push_back(cached_outputs_[i].display->display_id()); |
| 956 } | 905 } |
| 957 return state_controller_->GetStateForDisplayIds(display_ids); | 906 return state_controller_->GetStateForDisplayIds(display_ids); |
| 958 } | 907 } |
| 959 } | 908 } |
| 960 default: | 909 default: |
| 961 NOTREACHED(); | 910 NOTREACHED(); |
| 962 } | 911 } |
| 963 return OUTPUT_STATE_INVALID; | 912 return OUTPUT_STATE_INVALID; |
| 964 } | 913 } |
| 965 | 914 |
| 966 OutputConfigurator::CoordinateTransformation | 915 OutputConfigurator::CoordinateTransformation |
| 967 OutputConfigurator::GetMirrorModeCTM( | 916 OutputConfigurator::GetMirrorModeCTM(const DisplayState& output) { |
| 968 const OutputConfigurator::OutputSnapshot& output) { | |
| 969 CoordinateTransformation ctm; // Default to identity | 917 CoordinateTransformation ctm; // Default to identity |
| 970 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); | 918 const DisplayMode* native_mode_info = output.display->native_mode(); |
| 971 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); | 919 const DisplayMode* mirror_mode_info = output.mirror_mode; |
| 972 | 920 |
| 973 if (!native_mode_info || !mirror_mode_info || native_mode_info->height == 0 || | 921 if (!native_mode_info || !mirror_mode_info || |
| 974 mirror_mode_info->height == 0 || native_mode_info->width == 0 || | 922 native_mode_info->size().height() == 0 || |
| 975 mirror_mode_info->width == 0) | 923 mirror_mode_info->size().height() == 0 || |
| 924 native_mode_info->size().width() == 0 || |
| 925 mirror_mode_info->size().width() == 0) |
| 976 return ctm; | 926 return ctm; |
| 977 | 927 |
| 978 float native_mode_ar = static_cast<float>(native_mode_info->width) / | 928 float native_mode_ar = static_cast<float>(native_mode_info->size().width()) / |
| 979 static_cast<float>(native_mode_info->height); | 929 static_cast<float>(native_mode_info->size().height()); |
| 980 float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) / | 930 float mirror_mode_ar = static_cast<float>(mirror_mode_info->size().width()) / |
| 981 static_cast<float>(mirror_mode_info->height); | 931 static_cast<float>(mirror_mode_info->size().height()); |
| 982 | 932 |
| 983 if (mirror_mode_ar > native_mode_ar) { // Letterboxing | 933 if (mirror_mode_ar > native_mode_ar) { // Letterboxing |
| 984 ctm.x_scale = 1.0; | 934 ctm.x_scale = 1.0; |
| 985 ctm.x_offset = 0.0; | 935 ctm.x_offset = 0.0; |
| 986 ctm.y_scale = mirror_mode_ar / native_mode_ar; | 936 ctm.y_scale = mirror_mode_ar / native_mode_ar; |
| 987 ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5; | 937 ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5; |
| 988 return ctm; | 938 return ctm; |
| 989 } | 939 } |
| 990 if (native_mode_ar > mirror_mode_ar) { // Pillarboxing | 940 if (native_mode_ar > mirror_mode_ar) { // Pillarboxing |
| 991 ctm.y_scale = 1.0; | 941 ctm.y_scale = 1.0; |
| 992 ctm.y_offset = 0.0; | 942 ctm.y_offset = 0.0; |
| 993 ctm.x_scale = native_mode_ar / mirror_mode_ar; | 943 ctm.x_scale = native_mode_ar / mirror_mode_ar; |
| 994 ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5; | 944 ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5; |
| 995 return ctm; | 945 return ctm; |
| 996 } | 946 } |
| 997 | 947 |
| 998 return ctm; // Same aspect ratio - return identity | 948 return ctm; // Same aspect ratio - return identity |
| 999 } | 949 } |
| 1000 | 950 |
| 1001 OutputConfigurator::CoordinateTransformation | 951 OutputConfigurator::CoordinateTransformation |
| 1002 OutputConfigurator::GetExtendedModeCTM( | 952 OutputConfigurator::GetExtendedModeCTM(const DisplayState& output, |
| 1003 const OutputConfigurator::OutputSnapshot& output, | 953 const gfx::Point& new_origin, |
| 1004 int framebuffer_width, | 954 const gfx::Size& framebuffer_size) { |
| 1005 int framebuffer_height) { | |
| 1006 CoordinateTransformation ctm; // Default to identity | 955 CoordinateTransformation ctm; // Default to identity |
| 1007 const ModeInfo* mode_info = GetModeInfo(output, output.selected_mode); | 956 const DisplayMode* mode_info = output.selected_mode; |
| 1008 DCHECK(mode_info); | 957 DCHECK(mode_info); |
| 1009 if (!mode_info) | 958 if (!mode_info) |
| 1010 return ctm; | 959 return ctm; |
| 1011 // An example of how to calculate the CTM. | 960 // An example of how to calculate the CTM. |
| 1012 // Suppose we have 2 monitors, the first one has size 1366 x 768. | 961 // Suppose we have 2 monitors, the first one has size 1366 x 768. |
| 1013 // The second one has size 2560 x 1600 | 962 // The second one has size 2560 x 1600 |
| 1014 // The total size of framebuffer is 2560 x 2428 | 963 // The total size of framebuffer is 2560 x 2428 |
| 1015 // where 2428 = 768 + 60 (hidden gap) + 1600 | 964 // where 2428 = 768 + 60 (hidden gap) + 1600 |
| 1016 // and the sceond monitor is translated to Point (0, 828) in the | 965 // and the sceond monitor is translated to Point (0, 828) in the |
| 1017 // framebuffer. | 966 // framebuffer. |
| 1018 // X will first map input event location to [0, 2560) x [0, 2428), | 967 // X will first map input event location to [0, 2560) x [0, 2428), |
| 1019 // then apply CTM on it. | 968 // then apply CTM on it. |
| 1020 // So to compute CTM, for monitor1, we have | 969 // So to compute CTM, for monitor1, we have |
| 1021 // x_scale = (1366 - 1) / (2560 - 1) | 970 // x_scale = (1366 - 1) / (2560 - 1) |
| 1022 // x_offset = 0 / (2560 - 1) | 971 // x_offset = 0 / (2560 - 1) |
| 1023 // y_scale = (768 - 1) / (2428 - 1) | 972 // y_scale = (768 - 1) / (2428 - 1) |
| 1024 // y_offset = 0 / (2428 -1) | 973 // y_offset = 0 / (2428 -1) |
| 1025 // For Monitor 2, we have | 974 // For Monitor 2, we have |
| 1026 // x_scale = (2560 - 1) / (2560 - 1) | 975 // x_scale = (2560 - 1) / (2560 - 1) |
| 1027 // x_offset = 0 / (2560 - 1) | 976 // x_offset = 0 / (2560 - 1) |
| 1028 // y_scale = (1600 - 1) / (2428 - 1) | 977 // y_scale = (1600 - 1) / (2428 - 1) |
| 1029 // y_offset = 828 / (2428 -1) | 978 // y_offset = 828 / (2428 -1) |
| 1030 // See the unittest OutputConfiguratorTest.CTMForMultiScreens. | 979 // See the unittest OutputConfiguratorTest.CTMForMultiScreens. |
| 1031 ctm.x_scale = | 980 ctm.x_scale = static_cast<float>(mode_info->size().width() - 1) / |
| 1032 static_cast<float>(mode_info->width - 1) / (framebuffer_width - 1); | 981 (framebuffer_size.width() - 1); |
| 1033 ctm.x_offset = static_cast<float>(output.x) / (framebuffer_width - 1); | 982 ctm.x_offset = |
| 1034 ctm.y_scale = | 983 static_cast<float>(new_origin.x()) / (framebuffer_size.width() - 1); |
| 1035 static_cast<float>(mode_info->height - 1) / (framebuffer_height - 1); | 984 ctm.y_scale = static_cast<float>(mode_info->size().height() - 1) / |
| 1036 ctm.y_offset = static_cast<float>(output.y) / (framebuffer_height - 1); | 985 (framebuffer_size.height() - 1); |
| 986 ctm.y_offset = |
| 987 static_cast<float>(new_origin.y()) / (framebuffer_size.height() - 1); |
| 1037 return ctm; | 988 return ctm; |
| 1038 } | 989 } |
| 1039 | 990 |
| 1040 float OutputConfigurator::GetMirroredDisplayAreaRatio( | 991 float OutputConfigurator::GetMirroredDisplayAreaRatio( |
| 1041 const OutputConfigurator::OutputSnapshot& output) { | 992 const DisplayState& output) { |
| 1042 float area_ratio = 1.0f; | 993 float area_ratio = 1.0f; |
| 1043 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); | 994 const DisplayMode* native_mode_info = output.display->native_mode(); |
| 1044 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); | 995 const DisplayMode* mirror_mode_info = output.mirror_mode; |
| 1045 | 996 |
| 1046 if (!native_mode_info || !mirror_mode_info || native_mode_info->height == 0 || | 997 if (!native_mode_info || !mirror_mode_info || |
| 1047 mirror_mode_info->height == 0 || native_mode_info->width == 0 || | 998 native_mode_info->size().height() == 0 || |
| 1048 mirror_mode_info->width == 0) | 999 mirror_mode_info->size().height() == 0 || |
| 1000 native_mode_info->size().width() == 0 || |
| 1001 mirror_mode_info->size().width() == 0) |
| 1049 return area_ratio; | 1002 return area_ratio; |
| 1050 | 1003 |
| 1051 float width_ratio = static_cast<float>(mirror_mode_info->width) / | 1004 float width_ratio = static_cast<float>(mirror_mode_info->size().width()) / |
| 1052 static_cast<float>(native_mode_info->width); | 1005 static_cast<float>(native_mode_info->size().width()); |
| 1053 float height_ratio = static_cast<float>(mirror_mode_info->height) / | 1006 float height_ratio = static_cast<float>(mirror_mode_info->size().height()) / |
| 1054 static_cast<float>(native_mode_info->height); | 1007 static_cast<float>(native_mode_info->size().height()); |
| 1055 | 1008 |
| 1056 area_ratio = width_ratio * height_ratio; | 1009 area_ratio = width_ratio * height_ratio; |
| 1057 return area_ratio; | 1010 return area_ratio; |
| 1058 } | 1011 } |
| 1059 | 1012 |
| 1060 } // namespace ui | 1013 } // namespace ui |
| OLD | NEW |