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